# Dwellir API Documentation

> Enterprise-grade blockchain RPC infrastructure documentation. API references and implementation guides for Dwellir-supported networks. Authenticate HTTP and WebSocket connections with X-Api-Key or a key in the endpoint URL path. Use lowercase x-api-key metadata for gRPC.

# Dwellir API Documentation — Full Content

Complete offline reference for Dwellir's blockchain infrastructure documentation.

- 150+ supported networks
- 99.99% uptime SLA
- JSON-RPC compatible API endpoints
- HTTP and WebSocket API key in the X-Api-Key header or endpoint URL path
- gRPC API key in lowercase x-api-key metadata

Quick Start: Create an API key at https://dashboard.dwellir.com/register
HTTP and WebSocket header authentication: X-Api-Key: YOUR_API_KEY
HTTP and WebSocket URL path authentication: https://api-{network}.n.dwellir.com/YOUR_API_KEY
gRPC metadata authentication: x-api-key: YOUR_API_KEY

Site index: https://www.dwellir.com/llms.txt
Section index: https://www.dwellir.com/docs/llms.txt
Looking for guides? https://www.dwellir.com/guides/llms-full.txt

## Home

# Home

## Documentation Overview

### Core Concepts

- **[Getting Started Guide](https://www.dwellir.com/docs/getting-started)** - Quick setup and first steps
- **[Shared Node Pricing](https://www.dwellir.com/docs/getting-started/pricing)** - Metered plans for every project
- **[Unlimited Node Pricing](https://www.dwellir.com/docs/getting-started/unlimited-node-pricing)** - Unmetered endpoints at a fixed monthly price
- **[Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits)** - Understanding and managing limits
- **[Supported Chains](https://www.dwellir.com/docs/getting-started/supported-chains)** - 150+ blockchain networks
- **[CLI](https://www.dwellir.com/docs/cli)** - Manage keys, endpoints, and usage from your terminal

### Network Guides

Browse our comprehensive guides for supported networks:

#### Ethereum & Layer 2s

- **[Base L2](https://www.dwellir.com/docs/base)** - Complete Base Layer 2 documentation with JSON-RPC and Debug API methods
- **[Arbitrum One](https://www.dwellir.com/docs/arbitrum)** - Leading Ethereum L2 with comprehensive JSON-RPC and Debug API documentation
- **[World Chain](https://www.dwellir.com/docs/world-chain)** - Human-first Ethereum L2 with World ID integration for free gas and priority blockspace
- **[Avalanche C-Chain](https://www.dwellir.com/docs/avalanche)** - High-performance platform with sub-second finality and 4,500+ TPS
- **[Polygon PoS](https://www.dwellir.com/docs/polygon)** - Ethereum-compatible Layer 2 with massive ecosystem and ultra-low fees
- **[Unichain](https://www.dwellir.com/docs/unichain)** - Uniswap's DeFi-optimized L2 with built-in MEV protection and fast finality

#### Next-Generation Blockchains

- **[Aptos](https://www.dwellir.com/docs/aptos)** - Layer 1 blockchain with parallel execution, Move VM, and sub-second finality
- **[Sui Network](https://www.dwellir.com/docs/sui)** - Object-centric blockchain with parallel execution and sub-second finality
- **[HyperLiquid](https://www.dwellir.com/docs/hyperliquid)** - High-performance perpetuals DEX chain with native order book
- **[Bittensor](https://www.dwellir.com/docs/bittensor)** - Decentralized AI network with machine learning consensus
- **[IoTeX](https://www.dwellir.com/docs/iotex)** - Leading blockchain for IoT devices and DePIN infrastructure
- **[Manta Pacific](https://www.dwellir.com/docs/manta-pacific)** - EVM rollup with archive, trace, and debug RPC coverage
- **[Manta Atlantic](https://www.dwellir.com/docs/manta-atlantic)** - Polkadot zk identity parachain with enterprise archive RPC

More network documentation coming soon. Check our [supported chains](https://www.dwellir.com/docs/getting-started/supported-chains) for the full list of available networks.

### Best Practices

- **Rate Limiting** - Understand and optimize your API usage
- **Error Handling** - Robust error handling patterns
- **Security** - Secure key management and best practices
- **Performance** - Optimization tips for production workloads

## Need Help?

Our support team is available 24/7 to help you succeed:

- **Email** - <support@dwellir.com>
- **Documentation** - You're already here!

Start building with confidence on Dwellir's enterprise-grade infrastructure.

---

## Acala RPC with Dwellir

# Acala RPC with Dwellir

## Acala RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Acala supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Acala?

Acala is a DeFi-focused parachain on the Polkadot relay chain that provides a stablecoin (aUSD), liquid staking (LDOT), and EVM+Substrate interoperability. Built on Substrate, Acala exposes the standard JSON‑RPC namespaces developers rely on for production‑grade integrations.

### DeFi Primitives Out of the Box

- aUSD stablecoin, LDOT liquid staking, DEX and more, available through standard pallets and EVM.
- Seamless cross‑chain asset routing via XCM to and from Polkadot ecosystems.

### Familiar Tooling

- Works with polkadot.js, Subxt (Rust), and py‑substrate‑interface (Python).
- Dwellir provides globally anycasted endpoints with low‑latency routing and high availability.

### Security Inherited from Polkadot

- As parachain `2000` on Polkadot, Acala benefits from shared security and fast finality.

## Quick Start

Connect to Acala’s production endpoints.

### Installation & Setup

JavaScript (polkadot.js)
curl (HTTP JSON-RPC)
Rust (subxt)
Python (py-substrate-interface)

```ts
import { ApiPromise, WsProvider } from '@polkadot/api';

async function main() {
  const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });

  const [chain, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.version(),
  ]);

  console.log(`Connected to ${chain.toString()} v${version.toString()}`);

  // Subscribe to new blocks
  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    console.log(`New block #${header.number} ${header.hash.toHex()}`);
  });

  // Stop after 3 blocks
  setTimeout(async () => { await unsub(); await api.disconnect(); }, 18000);
}

main().catch(console.error);
```

```bash
curl -s https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let header = api.rpc().block_header(None).await?.expect("latest header");
    println!("Latest block: #{:?} (hash {:?})", header.number, header.hash());
    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(
    url="wss://api-acala.n.dwellir.com/YOUR_API_KEY",
    type_registry_preset="substrate-node-template"  # use custom types if needed
)

chain = substrate.rpc_request("system_chain", [])
print(f"Connected to {chain['result']}")

head = substrate.rpc_request("chain_getFinalizedHead", [])
print(f"Finalized head: {head['result']}")
```

## Network Information

| Parameter            | Value            | Details                                |
| -------------------- | ---------------- | -------------------------------------- |
| Genesis Hash         | 0xfc41b9bd…ba64c | Verified via chain\_getBlockHash(0)    |
| Native Token         | ACA              | 12 decimals                            |
| SS58 Prefix          | 10               | Address format                         |
| Runtime Spec Version | 2300             | state\_getRuntimeVersion (Oct 9, 2025) |
| Transaction Version  | 3                | state\_getRuntimeVersion               |
| Acala EVM explorer   | Acala Blockscout | blockscout.acala.network               |

Acala runs as Polkadot parachain `2000`. Token properties and address prefix were verified using `system_properties`; genesis hash via `chain_getBlockHash(0)`; runtime versions via `state_getRuntimeVersion` on October 9, 2025.

## API Reference

Acala exposes the core Substrate RPC namespaces for node telemetry, block production, storage access, and transaction submission.

## Common Integration Patterns

### Subscribe to Finality and New Heads

```ts
const unsubFinal = await api.rpc.chain.subscribeFinalizedHeads((h) =>
  console.log(`Finalized #${h.number} ${h.hash.toHex()}`)
);
const unsubNew = await api.rpc.chain.subscribeNewHeads((h) =>
  console.log(`New #${h.number}`)
);
```

### Paginate Large Storage Scans

```ts
const keys = await api.rpc.state.getKeysPaged(
  // System.Account prefix
  '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
  100,
  '0x',
  null
);
console.log('Fetched', keys.length, 'keys');
```

### Estimate Fees Before Broadcasting

```ts
const ext = api.tx.balances.transferAllowDeath('ADDRESS', 1_000_000_000_000);
const info = await api.rpc.payment.queryInfo(ext.toHex());
console.log(`PartialFee: ${info.partialFee.toHuman()}`);
```

## Performance Best Practices

- Prefer WebSocket connections for subscriptions and multi‑round queries.
- Cache runtime metadata and type bundles; reuse ApiPromise across requests.
- Use `state_getKeysPaged` for large map scans; avoid full‑chain scans.
- Implement reconnection/backoff and share a connection pool across services.

## Troubleshooting

- Connection refused: ensure your API key is appended and outbound TCP/443 is allowed.
- Invalid SS58: addresses must use prefix `10` for Acala.
- Type errors: refresh metadata after runtime upgrades (`api.runtimeVersion`).
- Extrinsic failed: decode dispatch error via `api.registry.findMetaError`.

## Smoke Tests

Run these minimal checks against production endpoints (captured Oct 9, 2025):

```bash
# Node health (peers ≈ 15, isSyncing false)
curl -s https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}'

# Latest block header (e.g. number ~ 9617916)
curl -s https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"chain_getHeader","params":[]}'

# Finalized head hash (e.g. 0xdcdcc29c…f13e7)
curl -s https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"chain_getFinalizedHead","params":[]}'

# Runtime versions (specVersion 2300, transactionVersion 3)
curl -s https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"state_getRuntimeVersion","params":[]}'
```

## Migration Guide (from Polkadot/Kusama)

- Endpoints: replace with `https://api-acala.n.dwellir.com/YOUR_API_KEY` or `wss://api-acala.n.dwellir.com/YOUR_API_KEY`.
- Addresses: re‑encode SS58 addresses with prefix `10`.
- Types: include Acala custom types where applicable; refresh metadata after upgrades.
- Fees: re‑calibrate using `payment_queryInfo`; fee multipliers differ across chains.

## Resources & Tools

- [Acala Portal](https://acala.network)
- [Acala EVM explorer](https://blockscout.acala.network/)
- [Substrate Developer Hub](https://docs.substrate.io/)
- [Dwellir Dashboard](https://dashboard.dwellir.com/register)

---

## author_pendingExtrinsics - Acala RPC Method

# author_pendingExtrinsics - Acala RPC Method

Returns all pending extrinsics currently in the transaction pool on Acala. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`author_pendingExtrinsics` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Acala
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Acala transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/acala/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/acala/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/acala/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Acala RPC Method

# author_rotateKeys - Acala RPC Method

Generate a new set of session keys on Acala. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`author_rotateKeys` is critical for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Validator Setup** - Generate initial session keys when setting up a new validator on decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Acala:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/acala/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/acala/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Acala RPC Method

# author_submitAndWatchExtrinsic - Acala RPC Method

Submits a signed extrinsic to Acala and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Acala
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

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

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-acala.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-acala.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-acala.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-acala.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/acala/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/acala/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/acala/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/acala/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Acala RPC Method

# author_submitExtrinsic - Acala RPC Method

Submits a fully signed extrinsic to Acala for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`author_submitExtrinsic` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Token Transfers** -- Send native tokens or assets between accounts on Acala
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

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

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-acala.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/acala/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/acala/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Acala RPC Method

# beefy_getFinalizedHead - Acala RPC Method

Returns the block hash of the latest BEEFY-finalized block on Acala. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`beefy_getFinalizedHead` is important for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

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

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/acala/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/acala/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/acala/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Acala RPC Method

# chain_getBlock - Acala RPC Method

Retrieves complete block information from Acala, including the block header, extrinsics, and justifications.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/acala/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/acala/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/acala/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Acala RPC Method

# chain_getBlockHash - Acala RPC Method

Returns the block hash for a given block number on Acala. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`chain_getBlockHash` is fundamental for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Acala
- **Block Navigation** - Navigate the blockchain history for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Acala
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Acala for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Acala state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Acala network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/acala/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/acala/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Acala RPC Method

# chain_getFinalizedHead - Acala RPC Method

Returns the hash of the last finalized block on Acala. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`chain_getFinalizedHead` is critical for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Acala
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-acala.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Acala:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/acala/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/acala/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/acala/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Acala RPC Method

# chain_getHeader - Acala RPC Method

Returns the block header for a given hash on Acala. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`chain_getHeader` is ideal for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Acala
- **Chain Synchronization** - Track block production and monitor chain progress for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Acala:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Acala chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Acala block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/acala/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/acala/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/acala/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Acala RPC Method

# chain_subscribeFinalizedHeads - Acala RPC Method

Subscribe to receive notifications when blocks are finalized on Acala. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Exchange Deposits** - Only credit funds after finalization for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-acala.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-acala.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-acala.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Acala:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/acala/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/acala/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/acala/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Acala RPC Method

# chain_subscribeNewHeads - Acala RPC Method

Subscribe to receive notifications when new block headers are produced on Acala. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`chain_subscribeNewHeads` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Block Monitoring** - Track new blocks in real time on Acala for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-acala.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-acala.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-acala.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Acala as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Acala:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/acala/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/acala/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/acala/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Acala RPC Method

# grandpa_roundState - Acala RPC Method

Returns the state of the current GRANDPA finality round on Acala when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`grandpa_roundState` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Acala, critical for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/acala/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/acala/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/acala/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/acala/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Acala RPC Method

# payment_queryFeeDetails - Acala RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Acala. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`payment_queryFeeDetails` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Acala
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/acala/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/acala/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/acala/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/acala/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Acala RPC Method

# payment_queryInfo - Acala RPC Method

Estimates the fee for an encoded extrinsic on Acala. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`payment_queryInfo` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Acala
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/acala/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/acala/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/acala/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/acala/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Acala RPC Method

# rpc_methods - Acala RPC Method

Returns a list of all RPC methods exposed by the Acala node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`rpc_methods` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Acala node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Acala endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-acala.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Acala endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/acala/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/acala/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/acala/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Acala RPC Method

# state_call - Acala RPC Method

Calls a runtime API function on Acala and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`state_call` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/acala/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/acala/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/acala/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/acala/system_version) -- Get the node version for compatibility checking

---

## state_getKeysPaged - Acala RPC Method

# state_getKeysPaged - Acala RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Acala. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`state_getKeysPaged` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Acala
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-acala.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/acala/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/acala/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Acala RPC Method

# state_getMetadata - Acala RPC Method

Returns the runtime metadata for Acala as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`state_getMetadata` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Acala
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Acala:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Acala:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/acala/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/acala/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Acala RPC Method

# state_getRuntimeVersion - Acala RPC Method

Returns the runtime version information for Acala, including the spec name, spec version, implementation version, and supported API versions.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`state_getRuntimeVersion` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Acala
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Acala in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/acala/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/acala/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Acala RPC Method

# state_getStorage - Acala RPC Method

Returns the SCALE-encoded storage value for a given key on Acala. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`state_getStorage` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Acala
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/acala/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/acala/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Acala RPC Method

# state_queryStorageAt - Acala RPC Method

Queries multiple storage keys at a specific block on Acala, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`state_queryStorageAt` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Acala
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/acala/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/acala/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/acala/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/acala/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Acala RPC Method

# system_chain - Acala RPC Method

Returns the chain name of the Acala network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`system_chain` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Network Verification** -- Confirm your application is connected to the correct Acala network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-acala.n.dwellir.com/YOUR_API_KEY', 'Acala');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/acala/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/acala/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/acala/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/acala/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/acala/rpc_methods) -- List all available RPC methods

---

## system_health - Acala RPC Method

# system_health - Acala RPC Method

Returns the health status of the Acala node, including peer count, sync state, and whether the node expects to have peers.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`system_health` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Acala
- **Load Balancing** - Route requests only to healthy, fully synced nodes for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-acala.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-acala.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Acala:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Acala nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-acala.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/acala/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/acala/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Acala RPC Method

# system_name - Acala RPC Method

Returns the node implementation name on Acala. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`system_name` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Acala
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Acala node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Acala node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Acala node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Acala node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Acala node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Acala nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/acala/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/acala/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/acala/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/acala/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/acala/rpc_methods) -- List all available RPC methods

---

## system_properties - Acala RPC Method

# system_properties - Acala RPC Method

Returns the chain-specific properties for Acala, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`system_properties` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Acala
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/acala/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/acala/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/acala/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/acala/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/acala/rpc_methods) -- List all available RPC methods

---

## system_version - Acala RPC Method

# system_version - Acala RPC Method

Returns the node implementation version string on Acala. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Acala?** Build on Polkadot's DeFi and liquidity hub with aUSD stablecoin and liquid staking (LDOT) with $250M aUSD ecosystem fund, 150%+ LDOT TVL growth, micro gas fees payable in any token, and Coinbase Cloud partnership.

## When to Use This Method

`system_version` is essential for DeFi developers, stablecoin builders, and teams requiring cross-chain liquidity:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Acala
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for decentralized stablecoin (aUSD), liquid DOT staking (LDOT), and cross-chain AMM DEX
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-acala.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-acala.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Acala node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-acala.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Acala node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-acala.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Acala node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-acala.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Acala node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-acala.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Acala node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Acala nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/acala/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/acala/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/acala/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/acala/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/acala/rpc_methods) -- List all available RPC methods

---

## Agent Tooling

# Agent Tooling

Dwellir builds tools and infrastructure that AI coding agents can use directly. This page covers the CLI, agent skills, migration automation, and the documentation endpoints that make Dwellir's docs consumable by agents without HTML parsing.

## Dwellir plugin

The [Dwellir plugin](https://www.dwellir.com/docs/agents/plugin) combines hosted account tools, blockchain RPC queries, and the existing Hyperliquid skill.
Version 0.1.0 is available for private testing. Public directory installation is not available yet.

## Standalone MCP server

Connect the [Dwellir MCP server](https://www.dwellir.com/docs/agents/mcp) directly from a compatible AI client.
It provides the same hosted account and blockchain tools without requiring the plugin or skills.
The hosted server and dashboard account approval are available in production.

## Agent Cookbook

The [Agent Cookbook](https://www.dwellir.com/guides/agent-cookbook) has copy-ready prompts for live feeds, dashboards, and reports on Dwellir.
Each prompt lists the checks the agent must pass before it runs live.

## Dwellir CLI

The [Dwellir CLI](https://www.dwellir.com/docs/cli) supports developers, CI automation, custom usage tooling, and coding agents.
Its standalone documentation covers command-line access to the Dwellir platform.
Every command supports both `--json` and `--toon` output.
In auto-detected non-interactive/agent environments, TOON is the default when no explicit output config exists.

Key capabilities for agents:

- **Endpoint discovery**: `dwellir endpoints list --json` returns the full catalog of 150+ blockchain endpoints with connection URLs, node types, and ecosystems.
- **API key management**: Create, rotate, and delete API keys programmatically with `dwellir keys create --name "agent-key" --json`. Output masks every key, so keys stay out of agent transcripts. `dwellir keys env agent-key` writes the key to `.env` without printing it.
- **Usage analytics**: Query request counts, RPS, costs, and error logs with structured TOON/JSON output.
- **Built-in docs**: `dwellir docs list` and `dwellir docs get <topic>` fetch Dwellir documentation as markdown directly in the terminal.

Agent-output benchmark details:

- Dwellir CLI benchmark run (Codex + Claude): [2026-03-03 JSON vs TOON benchmark](https://github.com/dwellir-public/cli/blob/main/docs/benchmarks/2026-03-03-agent-output-mode-json-vs-toon.md)
- TOON upstream benchmarks: [TOON benchmarks](https://github.com/toon-format/toon/tree/main/packages/toon#benchmarks)
- TOON caveats / when not to use: [When not to use TOON](https://github.com/toon-format/toon/tree/main/packages/toon#when-not-to-use-toon)

Install the CLI:

```bash
curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh
```

See the full [CLI documentation](https://www.dwellir.com/docs/cli) for all commands and flags.

## Hyperliquid Agent Skill

The [Hyperliquid agent skill](https://github.com/dwellir-public/hyperliquid-skills) gives AI coding agents procedural knowledge for building on Hyperliquid through Dwellir's infrastructure. It follows the open [Agent Skills standard](https://skills.sh), making it portable across 40+ AI coding agents including Claude Code, Cursor, and Windsurf.

### What the skill provides

Once installed, the skill automatically activates when an agent encounters Hyperliquid-related tasks. It equips the agent with knowledge of:

- **HyperEVM JSON-RPC**: Query EVM state, deploy Solidity contracts (Chain ID: 999, gas token: HYPE)
- **Info API**: Access market data, prices, order books, candles, funding rates, user positions and balances
- **gRPC streaming**: Stream real-time L1 block data, fill executions, and order book snapshots
- **Order book WebSocket**: Real-time L2 and L4 depth data from edge servers in Singapore and Tokyo
- **Native API routing**: The skill teaches agents to route read operations through Dwellir endpoints and write operations (orders, transfers) through Hyperliquid's native API with EIP-712 signatures

### Install

```bash
npx skills add dwellir-public/hyperliquid-skills
```

This installs the skill into your project's `.claude/skills/` directory. No manual invocation is needed.

- [View on Skills.sh](https://skills.sh/dwellir-public/hyperliquid-skills/hyperliquid)
- [GitHub repository](https://github.com/dwellir-public/hyperliquid-skills)
- [Hyperliquid API documentation](https://www.dwellir.com/docs/hyperliquid)

## RPC Migration Prompt

The migration prompt automates switching a project's blockchain RPC endpoints from other providers to Dwellir. Copy it into your AI agent's context or use it as a system prompt. It walks agents through a structured 5-phase process: environment discovery, codebase scanning, compatibility matching, migration, and summary reporting.

View and copy the migration prompt

```text
Migrate this project's blockchain RPC endpoints to Dwellir. Follow the phases below in order. Use subagents and background processes to parallelize work wherever your tooling supports it.

## Phase 1 — Environment & Endpoint Discovery

1. Check whether the Dwellir CLI is installed by running `dwellir --version`. If the command is not found, suggest the user install it:
   curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh
2. Obtain the full list of Dwellir-supported chains, networks, and node types (full vs archive). Try one of these approaches in order until one succeeds:
   a. **CLI** (preferred): Run `dwellir endpoints list` to get the complete endpoint catalog.
   b. **Documentation**: If the CLI is unavailable or the user declines to install it, fetch https://www.dwellir.com/docs.md or https://www.dwellir.com/networks.md for the supported endpoint list.
   c. **Dashboard export**: As a last resort, ask the user to go to dashboard.dwellir.com/endpoints and press the Export button (top-left) to export all endpoints as CSV, Markdown, or JSON, then share the file with you.
3. Check whether the project uses separate configurations per environment (production, staging, development, etc.). If it does, ask the user to provide a Dwellir API key for each environment. If there is only one environment, ask for a single key.

## Phase 2 — Codebase Discovery

Scan the entire codebase in parallel where possible:

1. Find every RPC endpoint URL (look for domains like infura.io, alchemy.com, quicknode.com, chainstack.com, ankr.com, blast.io, drpc.org, and any other known RPC providers, as well as raw IP/port patterns and chain-specific gateway URLs).
2. Identify each endpoint's chain, network, and authentication method (API key in URL path, header, query param, or none).
3. Determine whether the code requires an archive node or a full node for each endpoint (look for calls to historical state such as eth_getBalance at old block heights, debug_*/trace_* namespaces, or large block-range log filters).
4. Check if the codebase interacts with Hyperliquid. If it does, suggest that the user install Dwellir's Hyperliquid Skills: npx skills add https://github.com/dwellir-public/hyperliquid-skills

## Phase 3 — Compatibility Matching

For each discovered endpoint:

1. Compare the chain + network against the Dwellir endpoints list from Phase 1. Note that some providers (especially for EVM chains) use chain ID-based naming in their URLs rather than chain + network names — resolve any ambiguity by calling the endpoint's RPC method for chain ID (e.g., eth_chainId) and comparing the result against the chain ID returned by the corresponding Dwellir endpoint to confirm they serve the same network.
2. If the code requires an archive node and Dwellir only offers a full node for that chain, mark the endpoint as unsupported and do NOT migrate it.
3. For EVM chains, check whether the codebase depends on client-specific response shapes (e.g., Geth/Erigon trace formats vs Reth, differences in debug_traceTransaction output, or Parity-style trace_* responses). Use web search if needed to understand current client-level differences. Flag any potential incompatibilities.

## Phase 4 — Migration

1. Create a new branch (e.g., chore/migrate-to-dwellir) — NEVER commit directly to main.
2. For each supported endpoint, replace the provider URL with the equivalent Dwellir endpoint URL and update the authentication to use the correct Dwellir API key for each environment. Preserve the existing configuration pattern (env var, config file, etc.).
3. If any endpoints, chains, or networks in the codebase are NOT supported by Dwellir, do not touch them.

## Phase 5 — Summary

Present a clear summary with:

- Migrated: list of endpoints successfully switched to Dwellir (chain, network, full/archive).
- Flagged: any EVM client compatibility concerns the user should verify.
- Not supported: list of endpoints/chains/networks Dwellir does not currently support, along with whether each requires a full or archive node and the estimated monthly request volume if determinable from the code. Ask the user to reach out to support@dwellir.com or the team on https://t.me/dwellir with this list so Dwellir can evaluate adding support.

If there are any questions about supported RPC methods or Dwellir services, consult https://www.dwellir.com/docs/llms.txt and https://www.dwellir.com/docs.md for authoritative reference.

Commit the changes and ask the user whether you should push the branch to origin and open a pull request.
```

## Documentation for Agents

Dwellir's documentation is built with AI agent ergonomics in mind. Every page is available as clean markdown, and multiple discovery mechanisms help agents find the right content without HTML parsing.

### llms.txt

The site follows the [llmstxt.org](https://llmstxt.org) specification. Agents can fetch a structured index of all available content:

| Endpoint                                                            | Description                                                                     |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [`/llms.txt`](https://www.dwellir.com/llms.txt)                     | Site-wide index with links to all networks, blog posts, and documentation       |
| [`/docs/llms.txt`](https://www.dwellir.com/docs/llms.txt)           | Curated documentation index with network guides and key docs                    |
| [`/docs/llms-full.txt`](https://www.dwellir.com/docs/llms-full.txt) | Complete documentation concatenated into a single file for large-context agents |

### Markdown endpoints

Use the dedicated docs API endpoint or the existing `.md` shortcuts on networks and blog pages to get the content as plain markdown with `Content-Type: text/markdown` headers:

```
https://www.dwellir.com/api/docs/ethereum/markdown
https://www.dwellir.com/networks/ethereum.md
https://www.dwellir.com/blog/hyperliquid-rpc-providers.md
```

These endpoints strip all JSX/MDX components, rewrite internal links to absolute URLs, and include YAML frontmatter with title and description metadata.

### Smart 404 responses

When a documentation page is not found, the API returns fuzzy-matched suggestions instead of a generic error. Agents receive:

- A list of similar pages ranked by confidence score
- Direct links to the matching markdown URLs
- Fallback links to `/docs/llms.txt` and `/llms.txt` for broader discovery

Single exact matches (confidence 1.0) trigger an automatic redirect. This means minor typos or case mismatches resolve automatically.

### Content negotiation

All markdown endpoints set response headers that agents can use for content negotiation:

- `Content-Type: text/markdown; charset=utf-8`
- `Link` header with `rel="canonical"` (HTML version) and `rel="alternate"` (markdown version)
- `X-Robots-Tag: noindex, follow` to prevent search engine indexing of markdown versions

### Index endpoints

Two index endpoints provide structured lists of all available content:

- [`/docs.md`](https://www.dwellir.com/docs.md) - All documentation pages with titles, descriptions, and markdown links
- [`/networks.md`](https://www.dwellir.com/networks.md) - All supported networks with availability, regions, and pricing summaries

## Next steps

- [Install the CLI](https://www.dwellir.com/docs/cli/installation) and authenticate with `dwellir auth login`
- [Install the Hyperliquid skill](https://github.com/dwellir-public/hyperliquid-skills) for AI-assisted Hyperliquid development
- Fetch [`/llms.txt`](https://www.dwellir.com/llms.txt) to discover all available documentation
- [Contact the Dwellir team](mailto:support@dwellir.com) for dedicated node cluster access or custom integrations

---

## Dwellir MCP server

# Dwellir MCP server

The hosted Dwellir Model Context Protocol server gives AI clients access to account tools and blockchain data.
Connect it directly from an MCP client, or use it through the [Dwellir plugin](https://www.dwellir.com/docs/agents/plugin).
The standalone server does not require the plugin or its skills.

The hosted server and dashboard account approval are available in production.

## Connect a standalone client

Use an MCP client that supports remote Streamable HTTP servers and browser OAuth login.
Add this server URL to your client's MCP settings:

```text
https://mcp.dwellir.com/mcp
```

1. Start the connection from your client and sign in to Dwellir in the browser.
2. Check the requesting application on the dashboard.
3. Choose **Read only** or **Manage keys** from the access options your client requested.
4. Select **Authorize**. The browser returns to your client's callback automatically.
5. Return to your client and confirm that the connection completed.

You can create a Dwellir account during login.

Select your client:

Claude Code

Codex

OpenCode

Grok

Cursor

```sh title=""
claude mcp add --transport http --scope user dwellir https://mcp.dwellir.com/mcp
claude
# In Claude Code: /mcp → Dwellir → Authenticate
```

```sh title=""
codex mcp add dwellir --url https://mcp.dwellir.com/mcp
codex mcp login dwellir
```

```sh title=""
opencode mcp add dwellir --url https://mcp.dwellir.com/mcp
opencode mcp auth dwellir
```

```sh title=""
grok mcp add --transport http dwellir https://mcp.dwellir.com/mcp
grok
# In Grok: /mcps → Dwellir → press i to authenticate
```

```json title=""
{
  "mcpServers": {
    "dwellir": {
      "url": "https://mcp.dwellir.com/mcp"
    }
  }
}
```

For Cursor, merge the JSON into `.cursor/mcp.json`, then connect Dwellir in MCP settings.

Choose access in the dashboard from the scopes your client requests.

You do not need a local server or an API key in your client's configuration.
The hosted server uses your selected Dwellir key when it makes blockchain requests.
Those requests consume your account quota.

## Available tools

| Task                                    | Tools                                                 |
| --------------------------------------- | ----------------------------------------------------- |
| Find chains, networks, and endpoint IDs | `list_endpoints`                                      |
| Find supported read methods             | `rpc_methods`                                         |
| Query blockchain state                  | `rpc_call`                                            |
| Query supported Hyperliquid Info data   | `hyperliquid_info`                                    |
| Sample WebSocket updates                | `capture_stream`                                      |
| Inspect account usage                   | `usage_summary`, `usage_history`                      |
| Manage named API keys                   | `list_keys`, `create_key`, `update_key`, `delete_key` |
| Find current documentation              | `search_docs`, `get_docs`                             |

Discover an endpoint and an enabled key before making a chain query.
The server returns non-secret key references, which identify keys within MCP.
It does not return API key values in tool responses.
Disabling or deleting a key interrupts applications that use it.

Read methods cover EVM, Substrate, Solana, Bitcoin, Starknet, and Sui.
Method availability depends on the chain, endpoint, and account entitlements.
Unknown methods and transaction broadcasts are rejected.

WebSocket captures contain at most 20 messages and run for at most 15 seconds.
Continuous subscriptions and gRPC streams belong in application code.
Use the [Hyperliquid documentation](https://www.dwellir.com/docs/hyperliquid) for those protocols.

## Project setup

Your application needs credentials that work outside the MCP connection.
CLI 0.2.0 and later provide project setup through the [Dwellir CLI](https://www.dwellir.com/docs/cli).
The commands below require CLI 0.2.0 or later.

```sh
dwellir auth login --device-code
dwellir project setup --chain ethereum --network mainnet --create-key my-project
```

The CLI writes the key and endpoint URLs into a private, ignored environment file.
The project setup command omits credential values from its output.
Keep generated environment files out of chat.
Use `--key-name` to select an existing enabled key by name.
To write only the key, run `dwellir keys env my-project` (CLI 0.3.0 or later). It uses the same file rules as setup.

The CLI also supports human use, CI automation, and custom usage tooling.
It remains available independently of MCP and the plugin.

## Permissions and disconnecting

Read access supports account inspection and chain queries.
**Manage keys** also permits creating, updating, and deleting API keys.
A read-only request cannot gain key-management access during approval.
The MCP tools do not purchase subscriptions or execute trades.

Revoke the developer-tool credential from the dashboard's Agents page to end its account access.
Also remove the connection from your client. Removing local credentials alone may leave server access active.

## MCP or plugin?

Choose standalone MCP when you want tools in an existing MCP client.
Choose the [plugin](https://www.dwellir.com/docs/agents/plugin) when you also want Dwellir's reusable developer workflows and the canonical Hyperliquid skill.
Both use the same hosted account and blockchain tools.

---

## Dwellir plugin

# Dwellir plugin

The Dwellir plugin combines the [hosted MCP server](https://www.dwellir.com/docs/agents/mcp), account tools, and developer skills.
You can also connect the MCP server independently from a compatible client.
Use it to inspect RPC usage, query blockchain data, and manage API keys.

Version 0.2.0 is available from the public repository and GitHub release. Directory listings are pending.
The hosted MCP server and dashboard account approval are available in production.
The [Dwellir CLI](https://www.dwellir.com/docs/cli) and [Hyperliquid skill](https://github.com/dwellir-public/hyperliquid-skills) are available separately.

## How account access works

Connect your Dwellir account through the plugin's browser login flow.
Check the requesting application on the dashboard.
Choose **Read only** or **Manage keys** from the access options your client requested, then select **Authorize**.
The browser returns to your client's callback automatically.
Return to your client and confirm that the connection completed.
You can create an account during login.
Revoke access from the dashboard's Agents page when you finish.
Also remove the connection from your client. Removing local credentials alone may leave server access active.

With **Manage keys** access, the hosted server can create, rename, enable, disable, and delete API keys.
Read-only access permits listing keys and querying blockchain data.
It returns key names and non-secret references.
Direct blockchain queries use the selected key on the server and consume your account quota.

## Query blockchain data

Discover an endpoint before selecting a method.
The first release supports registered read methods across EVM, Substrate, Solana, Bitcoin, Starknet, and Sui.
Method support depends on the chain and endpoint.

For Hyperliquid, use the Info tool for supported queries.
The stream tool captures short WebSocket samples, including order book updates.
Samples contain at most 20 messages and run for at most 15 seconds.
Build continuous streams and gRPC clients in your project using the [Hyperliquid references](https://www.dwellir.com/docs/hyperliquid).

Example requests:

- "Show my Dwellir RPC usage this month."
- "Find an Ethereum mainnet endpoint and query the latest block."
- "Help me build a Hyperliquid order book consumer."
- "List my API key references without exposing key values."

## Project setup

Independent applications need their own API key configuration.
CLI 0.2.0 and later let your coding agent set up project credentials through the plugin workflow.
You do not need to copy credentials into chat.

The commands below require CLI 0.2.0 or later.

```sh
dwellir auth login --device-code
dwellir project setup --chain ethereum --network mainnet --create-key my-project
```

Use device login when a browser cannot reach a terminal's localhost callback.
For local development, the existing `dwellir auth login` flow remains available.

Project setup writes `DWELLIR_API_KEY`, `DWELLIR_RPC_URL`, and `DWELLIR_WSS_URL` into `.env`.
Use `--env-file .env.local` for frameworks that expect that filename.
Use `--key-name` to retrieve an existing enabled key by name.
To write only the key, run `dwellir keys env my-project` (CLI 0.3.0 or later). It uses the same file rules as setup.
The CLI adds an ignore rule and refuses tracked environment files.

Application code reads these environment variables.
The project setup command omits credential values from its output.
Keep generated environment files out of chat.
Store deployment credentials in your hosting provider's secret store.

## Skills and source

The plugin includes `dwellir`, `evm`, `substrate`, and `hyperliquid-data` skills.
They cover account tools, blockchain reads, and read-only data applications.
The package excludes trade execution, asset transfers, wallet signing, and automatic trading.
The Hyperliquid data skill remains maintained in its canonical repository.
Each plugin build copies that skill and its license unchanged from a pinned revision.

- [Canonical Hyperliquid data skill](https://github.com/dwellir-public/hyperliquid-skills/tree/main/skills/hyperliquid-data)
- [Dwellir CLI](https://github.com/dwellir-public/cli)
- [Agent tooling](https://www.dwellir.com/docs/agents)

---

## Aptos Network Documentation

# Aptos Network Documentation

## Aptos RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Aptos supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Aptos

- 160K+ TPS via Block-STM parallel execution
- Sub-second finality (\~250 ms blocks) with AptosBFT v4
- Resource-oriented Move language with formal verification
- Native sponsored and multi-agent transactions
- Object model for powerful composition
- Evolving token standards (Fungible Asset and Digital Asset)

## Quick Start

cURL
TypeScript SDK (@aptos-labs/ts-sdk)
Python SDK (aptos-sdk)
Rust SDK

```bash
curl -X GET https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1 \
  -H "Accept: application/json"
```

```ts
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.MAINNET,
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const info = await aptos.getLedgerInfo();
console.log(info.chain_id, info.ledger_version);
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
info = client.get_ledger_info()
print(info["chain_id"], info["ledger_version"])  # 1 APT = 100,000,000 Octas
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let info = client.get_ledger_information().await?;
println!("{} {}", info.inner().chain_id, info.inner().ledger_version);
```

## Network Information

| Parameter    | Value       | Details                   |
| ------------ | ----------- | ------------------------- |
| Chain ID     | 1           | Mainnet                   |
| Native Token | APT         | 1 APT = 100,000,000 Octas |
| Consensus    | AptosBFT v4 | \~250 ms blocks           |
| Execution    | Block-STM   | Parallel transactions     |

## REST API Reference

- Base path: `/v1`
- Auth: Add your key in the URL path: `https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1`
- JSON responses, snake\_case fields, bcs-encoded payloads for transactions

## GraphQL API Reference

- Indexer GraphQL endpoint: `https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql`
- Advanced queries for transactions, tokens, ANS, aggregations
- For a continuous transaction feed, use the gRPC Transaction Stream rather than polling GraphQL

See the GraphQL section for examples and schema notes.

## Transaction Stream Service

- Standard `aptos.indexer.v1.RawData/GetTransactions` server-streaming gRPC, using the upstream Aptos protobufs
- Server-side filtering with `BooleanTransactionFilter`, applied before delivery and before metering
- Live tail or replay from a stored ledger version, on the same RPC
- Authenticated with your existing dashboard key via `x-api-key` gRPC metadata
- Early access. Email `support@dwellir.com`, or see the [Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview)

## Move Development

- Entry functions (transactions) vs view functions (read-only)
- Modules, resources, and abilities (key, store, drop, copy)
- Testing with Move unit tests and Move Prover

## Object Model

- Globally addressable objects enable safe composition
- Reference types: `ConstructorRef`, `MutatorRef`, `DeleteRef`
- Ownership hierarchies and type-safe conversions

## Token Standards

- Legacy: `0x1::coin`, `0x3::token`
- Current: Fungible Asset (FA) and Digital Asset (DA)
- Migration patterns and compatibility tips

## Unique Aptos Features

- Sponsored transactions (fee payer)
- Multi-agent transactions (multiple signers)
- Key rotation (proven/unproven)
- Aggregator V2 counters
- Orderless transactions

## Code Examples

Find end-to-end examples for transfers, NFTs, module publish, and token ops in the respective sections.

## Performance Optimization

- Parallel-friendly design patterns (minimize write conflicts)
- Gas optimization via simulation and views
- Aggregators for scalable counters
- Batching reads and writes when appropriate

## Troubleshooting

- Common REST errors, transaction failures, module verification
- Gas estimation pitfalls and how to resolve them

## Resources & Tools

- Official SDKs (TS, Python, Rust)
- Explorers, faucets, testing tools, community links

---

## accounts_get

# accounts_get

## Overview

Returns core account information (sequence number and authentication key) for a given address.

## Endpoint

`GET /v1/accounts/{address}`

## Aptos-Specific Notes

- Accounts are resources; sequence numbers are required for building transactions.
- Addresses are 0x-prefixed hex strings; leading zeros are accepted.

## Request

### Path Parameters

| Name    | Type   | Required | Description                   |
| ------- | ------ | -------- | ----------------------------- |
| address | string | Yes      | Account address (e.g., `0x1`) |

### Query Parameters

None.

### Request Body

None.

## Response

### Success Response (200)

```
{
  "sequence_number": "string",
  "authentication_key": "string"
}
```

### Error Responses

| Status | Error Code          | Description            |
| ------ | ------------------- | ---------------------- |
| 400    | invalid\_input      | Invalid address format |
| 404    | account\_not\_found | Account doesn't exist  |
| 500    | internal\_error     | Server error           |

## Code Examples

cURL
Python
TypeScript
Rust SDK

```
curl -X GET https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1 \
  -H "Accept: application/json"
```

SDK

```
from aptos_sdk.client import RestClient
client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
account = client.account("0x1")
```

```
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
const aptos = new Aptos(new AptosConfig({ network: Network.MAINNET, fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1" }));
const account = await aptos.getAccountInfo({ accountAddress: "0x1" });
```

```
use aptos_sdk::rest_client::Client;
let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let account = client.get_account("0x1").await?;
```

## Common Use Cases

- Checking account existence before transactions
- Retrieving authentication keys for verification
- Getting sequence numbers for transaction building

## Related Endpoints

- accounts\_resources - Get account resources
- accounts\_modules - Get account modules

---

## accounts_module

# accounts_module

## Overview

Fetch a specific Move module published under an account by module name.

## Endpoint

`GET /v1/accounts/{address}/module/{module_name}`

## Request

### Path Parameters

| Name         | Type   | Required | Description                     |
| ------------ | ------ | -------- | ------------------------------- |
| address      | string | Yes      | Account address                 |
| module\_name | string | Yes      | Module name (no address prefix) |

## Code Examples

cURL
Python
TypeScript
Rust

```
curl -X GET https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/module/aptos_account \
  -H "Accept: application/json"
```

```
module = client.account_module("0x1", "aptos_account")
```

```
const m = await aptos.getAccountModule({ accountAddress: "0x1", moduleName: "aptos_account" });
```

```
let m = client.get_account_module("0x1", "aptos_account").await?;
```

## Response

### Success Response (200)

Returns a Move module object containing:

```json
{
  "bytecode": "0xa11ceb0b060000000...",
  "abi": {
    "address": "0x1",
    "name": "aptos_account",
    "friends": [],
    "exposed_functions": [...],
    "structs": [...]
  }
}
```

The ABI includes complete type information, function signatures, and struct definitions for the module.

### Error Responses

| Status | Error Code          | Description                           |
| ------ | ------------------- | ------------------------------------- |
| 400    | invalid\_input      | Invalid address or module name format |
| 404    | module\_not\_found  | Module doesn't exist at this address  |
| 404    | account\_not\_found | Account doesn't exist                 |

## Use Cases

This endpoint is essential for several blockchain development workflows:

1. **Smart Contract Verification**: Verify the bytecode and ABI of deployed modules to ensure they match expected implementations before interacting with them.

2. **ABI Discovery**: Retrieve complete type information and function signatures for integration with wallets, dapps, or SDKs without requiring the original Move source code.

3. **Upgrade Auditing**: Compare module versions across different ledger versions to track changes and validate upgrade compatibility rules.

4. **Development Tools**: IDE plugins and debugging tools use this endpoint to provide autocomplete, type checking, and inline documentation for on-chain modules.

5. **Security Analysis**: Security researchers analyze deployed module bytecode to identify potential vulnerabilities or verify formal verification properties.

6. **Cross-Contract Integration**: Before calling functions in another module, applications can inspect the ABI to ensure compatibility and understand input/output types.

## Best Practices

**Module Name Format**: The module name parameter should not include the address prefix. Use `aptos_account` not `0x1::aptos_account`.

**Caching Strategy**: Module bytecode rarely changes. Implement client-side caching with ledger version as the cache key to minimize API calls. Only refetch when you detect a module upgrade event.

**ABI Type Resolution**: When parsing generic types in the ABI, ensure your client handles nested generics like `CoinStore<AptosCoin>` correctly. Use the full type path for disambiguation.

**Version Pinning**: For production applications, consider querying modules at specific ledger versions rather than always using the latest state. This provides deterministic behavior even during network upgrades.

**Error Handling**: A 404 response could mean either the account doesn't exist or the module doesn't exist at that account. Check the error message to distinguish these cases.

## Performance Considerations

Module queries are relatively lightweight operations. The response size depends on module complexity - simple modules return a few KB, while complex framework modules may return 100KB+ of bytecode and ABI data. If you only need specific information from the ABI, consider parsing it client-side and caching the relevant portions.

The REST API serves modules from the node's storage layer with minimal processing overhead. Response times are typically under 100ms for hot data.

---

## accounts_modules

# accounts_modules

## Overview

Returns all Move modules published under an account. Each module includes its compiled bytecode and the ABI (Application Binary Interface) describing the module's structs, functions, and type parameters. This endpoint is fundamental for on-chain contract discovery, ABI-driven integrations, and upgrade auditing.

> **Operational note:** On Dwellir shared Aptos fullnodes, this route depends on indexer-backed helpers. If the upstream indexer reader is unavailable, requests can fail with `internal_error`. For production discovery workflows, keep a GraphQL fallback ready for large crawls and historical backfills.

## Endpoint

`GET /v1/accounts/{address}/modules`

## Aptos-Specific Notes

- Move modules are published to the address of the deploying account and become part of that account's on-chain state.
- Use this endpoint for ABI discovery, upgrade auditing, and verifying deployed contract interfaces.
- The `0x1` address contains all Aptos framework modules (coin, account, staking, governance, etc.).
- Module bytecode is the compiled Move output; decompilation is possible but not lossless.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# List all modules under the Aptos framework
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules" \
      -H "Accept: application/json"

    # List modules at a specific historical version
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules?ledger_version=50000000" \
      -H "Accept: application/json"
```

## Response Fields

- `bytecode` (`string, required`): Hex-encoded compiled Move bytecode
- `abi.name` (`string, required`): Module name
- `abi.address` (`string, required`): Address where the module is published
- `abi.exposed_functions` (`array, required`): Public and entry functions callable externally
- `abi.structs` (`array, required`): Struct definitions including fields and abilities
- `abi.friends` (`array, required`): Other modules granted friend access

## Successful Response

```json
[
  {
    "bytecode": "0xa11ceb0b...",
    "abi": {
      "address": "0x1",
      "name": "coin",
      "friends": ["0x1::aptos_coin"],
      "exposed_functions": [
        {
          "name": "balance",
          "visibility": "public",
          "is_entry": false,
          "is_view": true,
          "generic_type_params": [{ "constraints": [] }],
          "params": ["address"],
          "return": ["u64"]
        },
        {
          "name": "transfer",
          "visibility": "public",
          "is_entry": true,
          "is_view": false,
          "generic_type_params": [{ "constraints": [] }],
          "params": ["&signer", "address", "u64"],
          "return": []
        }
      ],
      "structs": [
        {
          "name": "CoinStore",
          "is_native": false,
          "abilities": ["key"],
          "generic_type_params": [{ "constraints": [] }],
          "fields": [
            { "name": "coin", "type": "0x1::coin::Coin<T0>" },
            { "name": "frozen", "type": "bool" }
          ]
        }
      ]
    }
  }
]
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid address format

### Error 2

- Code: `account_not_found`
- Description: Account does not exist

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# List all modules under the Aptos framework
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules" \
  -H "Accept: application/json"

# List modules at a specific historical version
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules?ledger_version=50000000" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Get all modules for an account
modules = client.account_modules("0x1")

# List module names
for mod in modules:
    print(f"Module: {mod['abi']['name']}")

# Extract entry functions from a specific module
for mod in modules:
    if mod["abi"]["name"] == "coin":
        for fn in mod["abi"]["exposed_functions"]:
            if fn["is_entry"]:
                print(f"  Entry: {fn['name']}({', '.join(fn['params'])})")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Get all modules published by an account
const modules = await aptos.getAccountModules({ accountAddress: "0x1" });
console.log(`Found ${modules.length} modules`);

// Find view functions for building read-only queries
for (const mod of modules) {
  for (const fn of mod.abi?.exposed_functions ?? []) {
    if (fn.is_view) {
      console.log(`View: ${mod.abi?.name}::${fn.name}`);
    }
  }
}
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let modules = client.get_account_modules("0x1").await?;
for module in modules.inner() {
    println!("Module: {}", module.abi.as_ref().unwrap().name);
}
```

## Use Cases

1. **ABI Discovery**: Dynamically discover the interface of any deployed contract without prior knowledge. Build generic tools that can interact with any Move module by reading its ABI at runtime.

2. **Upgrade Auditing**: Compare modules at different `ledger_version` values to detect what changed in a contract upgrade, including new functions, modified parameters, or structural changes.

3. **Contract Verification**: Verify that deployed bytecode matches expected source code by compiling locally and comparing bytecode hashes.

4. **SDK Generation**: Auto-generate type-safe client libraries from on-chain ABIs, ensuring your integration stays in sync with the deployed contract.

5. **Security Analysis**: Inspect exposed functions, their visibility levels, and parameter types to assess the attack surface of a smart contract before interacting with it.

6. **Protocol Integration**: Before integrating with a DeFi protocol or NFT marketplace, fetch its modules to understand available entry points, required arguments, and return types.

## Best Practices

**Large Accounts**: Framework addresses like `0x1` publish dozens of modules. Use pagination (`limit` and `start`) to control response size, or fetch a single module by name using the `accounts_module` endpoint. If the shared indexer path is unavailable, fall back to GraphQL for complete catalog exports.

**Bytecode Size**: Bytecode strings can be large (10KB-500KB per module). If you only need the ABI, parse the `abi` field and discard `bytecode` to reduce memory usage.

**Historical Versions**: When auditing upgrades, query at the version before and after the upgrade transaction to see exactly what changed. Find the upgrade transaction version from the account's transaction history.

**Type Parameters**: Generic type parameters in functions and structs use positional references (`T0`, `T1`). Map these to the `generic_type_params` array for constraint information.

**Friend Modules**: The `friends` list shows which other modules have privileged access. This is important for security audits -- friend functions can bypass normal visibility restrictions.

**Caching**: Module bytecode changes only when the module is upgraded. Cache aggressively and invalidate when you detect an upgrade transaction for the account.

## Performance Considerations

Fetching all modules for an account can be slow for addresses with many deployments. The `0x1` framework address has 50+ modules, resulting in responses of 1-5MB and response times of 200-500ms.

For single-module lookups, use `GET /v1/accounts/{address}/module/{module_name}` instead, which returns in 50-100ms with a much smaller payload.

Bytecode dominates response size. If you only need the ABI (function signatures, struct definitions), consider fetching the full response once and caching the ABIs separately.

## Related Endpoints

- `/v1/accounts/{address}/module/{module_name}` - Get a single module by name
- `/v1/accounts/{address}/resources` - Get account resources (runtime state of modules)
- `/v1/accounts/{address}` - Get account info including authentication key
- `/v1/view` - Call view functions discovered through module ABIs

---

## accounts_resource

# accounts_resource

## Overview

Fetch a specific resource stored under an account by its full Move type string. Resources are the primary state-storage mechanism in Move -- every token balance, NFT collection, staking position, and application-specific datum is stored as a typed resource under an account address. This endpoint provides direct, type-safe access to individual resources.

## Endpoint

`GET /v1/accounts/{address}/resource/{resource_type}`

## Aptos-Specific Notes

- Resource types follow the format `address::module::StructName<TypeArgs>`.
- Generic types must include full type parameters, such as `0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>`.
- The resource type string must be URL-encoded when it contains special characters like `<`, `>`, or `::`.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Get APT balance for an account that actually stores AptosCoin
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/YOUR_ACCOUNT_ADDRESS/resource/0x1::coin::CoinStore%3C0x1::aptos_coin::AptosCoin%3E" \
      -H "Accept: application/json"

    # Get account metadata
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resource/0x1::account::Account" \
      -H "Accept: application/json"

    # Get DKG state (no URL encoding needed for simple types)
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resource/0x1::dkg::DKGState" \
      -H "Accept: application/json"
```

## Response Fields

- `type` (`string, required`): The fully qualified Move type of the resource
- `data` (`object, required`): The resource's fields serialized as JSON
- `data.coin.value` (`string, required`): For CoinStore, the balance in the smallest unit (octas for APT)
- `data.frozen` (`boolean, required`): For CoinStore, whether transfers are frozen
- `data.deposit_events` (`object, required`): Event handle for tracking deposits
- `data.withdraw_events` (`object, required`): Event handle for tracking withdrawals

## Successful Response

```json
{
  "type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
  "data": {
    "coin": {
      "value": "1500000000"
    },
    "deposit_events": {
      "counter": "42",
      "guid": {
        "id": {
          "addr": "0x1",
          "creation_num": "2"
        }
      }
    },
    "withdraw_events": {
      "counter": "15",
      "guid": {
        "id": {
          "addr": "0x1",
          "creation_num": "3"
        }
      }
    },
    "frozen": false
  }
}
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid address or malformed resource type string

### Error 2

- Code: `resource_not_found`
- Description: Resource type does not exist under this account

### Error 3

- Code: `account_not_found`
- Description: Account does not exist

## Common Resource Types

| Resource Type                                      | Description                                            |
| -------------------------------------------------- | ------------------------------------------------------ |
| `0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>` | APT token balance                                      |
| `0x1::account::Account`                            | Account metadata (sequence number, authentication key) |
| `0x1::staking_contract::StakingGroupContainer`     | Staking positions                                      |
| `0x1::token::TokenStore`                           | Legacy token (NFT) storage                             |
| `0x4::collection::Collection`                      | Digital Asset (NFT) collection                         |
| `0x1::coin::CoinInfo<0x1::aptos_coin::AptosCoin>`  | APT coin metadata (decimals, name, symbol)             |
| `0x1::stake::StakePool`                            | Validator stake pool info                              |
| `0x1::dkg::DKGState`                               | Distributed key generation state                       |

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Get APT balance for an account that actually stores AptosCoin
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/YOUR_ACCOUNT_ADDRESS/resource/0x1::coin::CoinStore%3C0x1::aptos_coin::AptosCoin%3E" \
  -H "Accept: application/json"

# Get account metadata
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resource/0x1::account::Account" \
  -H "Accept: application/json"

# Get DKG state (no URL encoding needed for simple types)
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resource/0x1::dkg::DKGState" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Get APT balance
resource = client.account_resource(
    "YOUR_ACCOUNT_ADDRESS",
    "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>"
)
balance_octas = int(resource["data"]["coin"]["value"])
balance_apt = balance_octas / 100_000_000
print(f"Balance: {balance_apt} APT")

# Get account sequence number
account = client.account_resource("0x1", "0x1::account::Account")
print(f"Sequence number: {account['data']['sequence_number']}")

# Get resource at a historical version
import requests
response = requests.get(
    "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resource/0x1::dkg::DKGState",
    params={"ledger_version": "50000000"},
    headers={"Accept": "application/json"}
)
historical = response.json()
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Get APT balance
const resource = await aptos.getAccountResource({
  accountAddress: "YOUR_ACCOUNT_ADDRESS",
  resourceType: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
});
const balanceOctas = BigInt(resource.coin.value);
console.log(`Balance: ${Number(balanceOctas) / 1e8} APT`);

// Get account info
const account = await aptos.getAccountResource({
  accountAddress: "0x1",
  resourceType: "0x1::account::Account",
});
console.log(`Sequence: ${account.sequence_number}`);
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

// Get a specific resource
let resource = client
    .get_account_resource("0x1", "0x1::dkg::DKGState")
    .await?;
println!("{:?}", resource.inner());

// Get APT coin store
let coin_store = client
    .get_account_resource("YOUR_ACCOUNT_ADDRESS", "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>")
    .await?;
```

## Use Cases

1. **Balance Checking**: Read `CoinStore` resources to check token balances for any fungible asset (APT, USDC, custom tokens) before initiating transfers or swaps.

2. **State Inspection**: Read application-specific resources to check contract state without executing transactions -- useful for displaying DeFi positions, staking info, or governance data in UIs.

3. **Historical State Queries**: Use the `ledger_version` parameter to read resource state at any historical point, enabling time-series analysis and state reconstruction.

4. **Event Handle Discovery**: Extract event handle creation numbers from resource fields to set up event monitoring via the events endpoints.

5. **Pre-Transaction Validation**: Check resource existence and values before building transactions. For example, verify a CoinStore exists before attempting a transfer to avoid unnecessary gas costs.

6. **Protocol Monitoring**: Monitor key protocol resources (treasury balances, governance parameters, oracle prices) for dashboards and alerting systems.

## Best Practices

**URL Encoding**: Resource types containing `<` and `>` (generics) must be URL-encoded. Use `%3C` for `<` and `%3E` for `>`. Most HTTP libraries handle this automatically.

**Type Precision**: The resource type must match exactly as stored on-chain, including the full address prefix. `coin::CoinStore` will not work; use `0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>`.

**Version Pinning**: When reading multiple related resources that must be consistent (such as balance and allowance), pass the same `ledger_version` to all requests to get an atomic snapshot.

**404 Handling**: A 404 for a CoinStore means the account has never held that token (the store has not been created), not that the balance is zero. Distinguish between "not registered" and "zero balance" in your application logic.

**Large Resources**: Some resources (like tables or large vectors) can be very large. If you only need a specific field, consider using the `view` endpoint to call a view function that returns just the data you need.

**Numeric Values**: All large numbers (balances, timestamps, IDs) are returned as strings to avoid JavaScript precision loss. Parse with BigInt or appropriate large-number libraries.

## Performance Considerations

Single resource lookups are highly optimized, completing in 30-80ms. The response size depends on the resource structure: simple resources like `Account` return under 1KB, while complex resources with large vectors or nested structs can be 10-100KB.

For applications that need multiple resources from the same account, it may be more efficient to use `GET /v1/accounts/{address}/resources` to fetch all resources in a single request, then filter client-side. However, for accounts with many resources (like `0x1`), targeted single-resource queries are faster.

Historical queries (with `ledger_version`) may be slightly slower than current-state queries if the node needs to read from archived storage.

## Related Endpoints

- `/v1/accounts/{address}/resources` - Get all resources under an account
- `/v1/accounts/{address}/module/{module_name}` - Get module ABI to discover resource types
- `/v1/view` - Call view functions for computed resource data
- `/v1/tables/{handle}/item` - Read individual table entries within resources

---

## accounts_resources

# accounts_resources

## Overview

Lists all Move resources stored under an account. Useful to discover balances, capabilities, and custom module data.

## Endpoint

`GET /v1/accounts/{address}/resources`

## Aptos-Specific Notes

- Resource types follow `address::module::Struct<...>`.
- Large accounts may have many resources; use pagination parameters if present.

## Request

### Path Parameters

| Name    | Type   | Required | Description                   |
| ------- | ------ | -------- | ----------------------------- |
| address | string | Yes      | Account address (e.g., `0x1`) |

### Query Parameters

| Name            | Type    | Required | Description                       |
| --------------- | ------- | -------- | --------------------------------- |
| ledger\_version | string  | No       | Read at a historical version      |
| limit           | integer | No       | Max number of resources to return |
| start           | string  | No       | Cursor for pagination             |

### Request Body

None.

## Response

### Success Response (200)

```
[
  {
    "type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
    "data": { "coin": { "value": "123" } }
  }
]
```

### Error Responses

| Status | Error Code          | Description            |
| ------ | ------------------- | ---------------------- |
| 400    | invalid\_input      | Invalid address format |
| 404    | account\_not\_found | Account doesn't exist  |

## Code Examples

cURL
Python
TypeScript
Rust SDK

```
curl -X GET https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resources?limit=100 \
  -H "Accept: application/json" \
  -H "Accept: application/json"
```

SDK

```
from aptos_sdk.client import RestClient
client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
resources = client.account_resources("0x1")
```

```
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
const aptos = new Aptos(new AptosConfig({ network: Network.MAINNET, fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1" }));
const resources = await aptos.getAccountResources({ accountAddress: "0x1" });
```

```
use aptos_sdk::rest_client::Client;
let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let resources = client.get_account_resources_bcs("0x1").await?;
```

## Common Use Cases

- Token balances (CoinStore, FA)
- Capability checks
- Reading application state

## Related Endpoints

- accounts\_resource - Get a single resource type

---

## accounts_transactions

# accounts_transactions

## Overview

Returns committed transactions where the account is the sender. This is the canonical REST endpoint for building account activity feeds, transaction history pages, reconciliation jobs, and "recent actions" views keyed to one Aptos address.

> **Operational note:** On Dwellir shared Aptos fullnodes, this route depends on indexer-backed history readers. If the node reports `Indexer reader is None` or another `internal_error`, switch to [GraphQL](https://www.dwellir.com/docs/aptos/graphql/overview) for indexed account history.

## Endpoint

`GET /v1/accounts/{address}/transactions`

Use this endpoint when you want all transactions submitted by one account and you do not need cross-account joins. If you need a specific transaction by hash, use [`transactions_by_hash`](https://www.dwellir.com/docs/aptos/transactions_by_hash). If you need indexed analytics or richer joins, use [GraphQL](https://www.dwellir.com/docs/aptos/graphql/overview).

## Request Parameters

- `address` (`string, required`): Path parameter: Aptos account address for the sender whose committed transactions you want to page through
- `start` (`string, optional`): Query parameter: Starting cursor for pagination
- `limit` (`integer, optional`): Query parameter: Maximum number of transactions to return in one page

## Request Example

```bash
# Get the latest 25 transactions for an account
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/transactions?limit=25" \
      -H "Accept: application/json"

    # Paginate from a specific sequence number
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/transactions?start=100&limit=50" \
      -H "Accept: application/json"
```

## Response Fields

- `result` (`OBJECT, required`): Each item in the response is a committed transaction object. For `user_transaction` entries, the most commonly-used fields are: ```json [ { "version": "238497201", "hash": "0x5bb5d8f4...", "type": "user_transaction", "sender": "0x1", "sequence_number": "352", "max_gas_amount": "2000", "gas_used": "8", "success": true, "vm_status": "Executed successfully", "timestamp": "1736443872382624" } ] ``` For account history pages, `version`, `hash`, `sequence_number`, `success`, and `timestamp` are usually enough to render a first-pass list. Pull the full transaction by hash only when the user opens a detail view.

## Successful Response

```json
[
  {
    "version": "238497201",
    "hash": "0x5bb5d8f4...",
    "type": "user_transaction",
    "sender": "0x1",
    "sequence_number": "352",
    "max_gas_amount": "2000",
    "gas_used": "8",
    "success": true,
    "vm_status": "Executed successfully",
    "timestamp": "1736443872382624"
  }
]
```

## Response Shape

Each item in the response is a committed transaction object. For `user_transaction` entries, the most commonly-used fields are:

```json
[
  {
    "version": "238497201",
    "hash": "0x5bb5d8f4...",
    "type": "user_transaction",
    "sender": "0x1",
    "sequence_number": "352",
    "max_gas_amount": "2000",
    "gas_used": "8",
    "success": true,
    "vm_status": "Executed successfully",
    "timestamp": "1736443872382624"
  }
]
```

For account history pages, `version`, `hash`, `sequence_number`, `success`, and `timestamp` are usually enough to render a first-pass list. Pull the full transaction by hash only when the user opens a detail view.

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Get the latest 25 transactions for an account
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/transactions?limit=25" \
  -H "Accept: application/json"

# Paginate from a specific sequence number
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/transactions?start=100&limit=50" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Fetch recent transactions
txns = client.get_account_transactions("0x1", params={"limit": 25})
for txn in txns:
    print(f"Seq {txn['sequence_number']}: {txn['payload']['function']} - {txn['vm_status']}")

# Paginate through all account transactions
all_txns = []
start = None
while True:
    params = {"limit": 100}
    if start is not None:
        params["start"] = start
    batch = client.get_account_transactions("0x1", params=params)
    if not batch:
        break
    all_txns.extend(batch)
    start = str(int(batch[-1]["sequence_number"]) + 1)
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Fetch recent transactions
const txns = await aptos.getAccountTransactions({
  accountAddress: "0x1",
  options: { offset: 0, limit: 25 }
});
console.log(`Found ${txns.length} transactions`);

// Process each transaction
for (const txn of txns) {
  console.log(`Version ${txn.version}: ${txn.success ? "OK" : "FAILED"}`);
}
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let txns = client.get_account_transactions("0x1", None, Some(25)).await?;
for txn in txns.inner() {
    println!("Seq {}: {}", txn.sequence_number, txn.vm_status);
}
```

## Pagination Guide

This endpoint paginates by sequence number using `start` and `limit`:

1. **First page**: Omit `start` to begin at the account's earliest committed transactions.
2. **Next page**: Use `last_sequence_number + 1` as the next `start` value.
3. **End detection**: An empty array or a short page means you have reached the end of the account's committed sender history.

Sequence numbers are per-sender and increment by 1 for every committed transaction from that account.

## Practical Guidance

- This endpoint is sender-scoped. It does not show incoming transfers or third-party activity that merely touched the account.
- For first-pass account history, render `version`, `hash`, `sequence_number`, `success`, and `timestamp`, then fetch a single transaction detail only when the user drills in.
- For richer joins or cross-account analytics, use Aptos GraphQL instead of repeatedly walking sender histories.

**Sequence Number Gaps**: If the account has failed transactions (which still consume gas and increment the sequence number), they appear in the results with `success: false`. Account for these when building activity feeds.

**Limit Selection**: Use `limit=100` for bulk retrieval to minimize API calls. Use smaller limits (10-25) for UI pagination where you display a few items per page.

**Caching Strategy**: Older transactions are immutable. Cache pages of historical transactions permanently and only re-fetch the latest page to check for new transactions.

**Address Normalization**: Ensure addresses are fully expanded to 66 characters (0x + 64 hex digits) with leading zeros. Short-form addresses like `0x1` are accepted but normalizing avoids inconsistencies.

## Performance Considerations

Query response time scales with the `limit` parameter. Fetching 25 transactions typically completes in 50-100ms, while 100 transactions may take 100-200ms depending on transaction complexity and payload sizes.

Accounts with thousands of transactions can be paginated efficiently because sequence numbers provide a natural index. The database uses the (address, sequence\_number) pair as a primary key, making lookups O(1) for any page.

For accounts with high transaction volume, consider storing the last-seen sequence number in your application and only fetching new transactions since that point.

## Related Endpoints

- `/v1/accounts/{address}` - Get account info including current sequence number
- `/v1/accounts/{address}/resources` - Get account resources (balances, state)
- `/v1/accounts/{address}/events/{creation_number}` - Get events for an account
- `/v1/transactions/by_hash/{hash}` - Look up a specific transaction by hash

## What to Watch For

- This endpoint is sender-scoped. Incoming transfers are not guaranteed to appear unless the queried account actually submitted the transaction.
- Results are committed ledger history, so this is the right source for confirmed account activity rather than pending transaction tracking.
- Keep `limit` small while developing. System accounts such as `0x1` can return large histories quickly.
- Use the cursor fields your client already stores for pagination instead of re-reading from the beginning on every sync.
- Treat GraphQL as the fallback for bulk history jobs if the shared node's indexer-backed reader is unavailable.

## Practical Patterns

### Activity Feed

Use `limit` plus your last stored cursor to incrementally extend an account history view without re-fetching older pages.

### Retry and Reconciliation

If your application stores transaction hashes after submission, compare the stored sender and sequence number against this endpoint to verify that account history is complete.

### Compliance and Auditing

Because the response is committed ledger data, it is suitable for downstream audit logs and reconciliation jobs that should not include mempool noise.

## Related Endpoints

- [transactions\_by\_hash](https://www.dwellir.com/docs/aptos/transactions_by_hash) for one known transaction
- [blocks\_by\_height](https://www.dwellir.com/docs/aptos/blocks_by_height) for block-scoped reads
- [GraphQL Overview](https://www.dwellir.com/docs/aptos/graphql/overview) for indexed history and analytics

---

## aggregations

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# aggregations

GraphQL aggregations enable powerful analytical queries on Aptos blockchain data, allowing you to compute statistics, counts, sums, and other aggregate functions across large datasets. These queries are essential for building analytics dashboards, generating reports, and understanding on-chain activity patterns without processing individual records.

## Overview

The Aptos GraphQL indexer provides aggregate functions that operate on filtered datasets, enabling you to answer questions like "How many transactions occurred today?", "What's the total trading volume?", or "Who are the top gas consumers?" These aggregations run efficiently on indexed data, providing fast results even for complex queries spanning millions of records.

## Common Aggregate Functions

The GraphQL API supports standard aggregate operations:

**count**: Total number of records matching criteria
**sum**: Sum of numeric field values
**avg**: Average of numeric values
**max**: Maximum value in dataset
**min**: Minimum value in dataset
**stddev**: Standard deviation of values
**variance**: Variance of values

## Example Queries

### Transaction Volume Analysis

```graphql
query TransactionMetrics($startTime: timestamp!, $endTime: timestamp!) {
  user_transactions_aggregate(
    where: {
      timestamp: { _gte: $startTime, _lte: $endTime }
    }
  ) {
    aggregate {
      count
      sum { gas_used }
      avg { gas_used }
      max { gas_used }
      min { gas_used }
    }
  }
}
```

### Top Gas Consumers

```graphql
query TopGasUsers($limit: Int!) {
  user_transactions_aggregate {
    aggregate { count }
  }
  user_transactions(
    order_by: { gas_used: desc },
    limit: $limit
  ) {
    sender
    gas_used
    version
    timestamp
  }
}
```

### Daily Active Users

```graphql
query DailyActiveUsers($date: date!) {
  user_transactions_aggregate(
    distinct_on: sender,
    where: {
      timestamp: {
        _gte: $date,
        _lt: "${date + 1 day}"
      }
    }
  ) {
    aggregate {
      count(distinct: true, columns: sender)
    }
  }
}
```

### Token Transfer Statistics

```graphql
query TokenTransferStats($token_type: String!) {
  coin_activities_aggregate(
    where: {
      coin_type: { _eq: $token_type },
      activity_type: { _eq: "0x1::coin::WithdrawEvent" }
    }
  ) {
    aggregate {
      count
      sum { amount }
      avg { amount }
    }
  }
}
```

### NFT Collection Analytics

```graphql
query CollectionMetrics($collection_id: String!) {
  current_token_ownerships_v2_aggregate(
    where: {
      current_token_data: {
        collection_id: { _eq: $collection_id }
      }
    }
  ) {
    aggregate {
      count
    }
  }

  token_activities_v2_aggregate(
    where: {
      token_data_id: { _like: "${collection_id}%" },
      type: { _eq: "0x3::token::MintTokenEvent" }
    }
  ) {
    aggregate {
      count
    }
  }
}
```

## Real-World Use Cases

1. **Protocol Analytics**: Track total value locked, transaction volumes, user growth, and other key metrics for DeFi protocols and dApps.

2. **User Behavior Analysis**: Understand user engagement patterns, identify power users, and analyze transaction frequency distributions.

3. **Gas Optimization Research**: Analyze gas consumption patterns to identify optimization opportunities and compare efficiency across different contract designs.

4. **Market Intelligence**: Aggregate trading volumes, price movements, and liquidity metrics for tokens and NFT collections.

5. **Network Health Monitoring**: Track transaction success rates, average confirmation times, and network utilization over time.

6. **Revenue Reporting**: Calculate total fees collected, transaction counts by type, and other financial metrics for business reporting.

## Best Practices

**Use Appropriate Filters**: Apply WHERE clauses to reduce dataset size before aggregation for better performance.

**Leverage Indexed Fields**: Aggregations on indexed fields (addresses, timestamps, types) perform significantly faster.

**Batch Time-Series Queries**: For dashboards displaying multiple time periods, batch queries together to reduce API calls.

**Cache Results**: Aggregate statistics change slowly - implement appropriate caching strategies to reduce load.

**Pagination for Details**: When showing aggregate summaries plus details, paginate the detail results appropriately.

**Use Variables**: Parameterize queries with GraphQL variables for reusable, type-safe queries.

## Performance Considerations

- Aggregations on large unfiltered tables can be slow - always use WHERE clauses
- Distinct counts are more expensive than simple counts
- Complex nested aggregations should be avoided or split into multiple queries
- Consider using materialized views for frequently accessed aggregations
- Time-range queries on timestamp fields are well-optimized

## Combining Aggregates with Details

```graphql
query DashboardMetrics($limit: Int!) {
  # Overall statistics
  metrics: user_transactions_aggregate {
    aggregate {
      count
      avg { gas_used }
      sum { gas_used }
    }
  }

  # Top performers
  top_users: user_transactions(
    order_by: { gas_used: desc },
    limit: $limit,
    distinct_on: sender
  ) {
    sender
    gas_used
  }

  # Recent activity
  recent: user_transactions(
    order_by: { timestamp: desc },
    limit: $limit
  ) {
    hash
    sender
    timestamp
    success
  }
}
```

## TypeScript Integration

```typescript
import { ApolloClient, gql } from "@apollo/client";

const client = new ApolloClient({
  uri: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql"
});

const TRANSACTION_STATS = gql`
  query TransactionStats {
    user_transactions_aggregate {
      aggregate {
        count
        avg { gas_used }
      }
    }
  }
`;

const { data } = await client.query({ query: TRANSACTION_STATS });
console.log(`Total transactions: ${data.user_transactions_aggregate.aggregate.count}`);
console.log(`Average gas: ${data.user_transactions_aggregate.aggregate.avg.gas_used}`);
```

## Related Concepts

- [GraphQL Overview](https://www.dwellir.com/docs/aptos/graphql/overview) - Introduction to GraphQL indexer
- [User Transactions](https://www.dwellir.com/docs/aptos/user_transactions) - Query transaction data
- [Token Activities](https://www.dwellir.com/docs/aptos/token_activities) - Aggregate token transfers
- [ANS Queries](https://www.dwellir.com/docs/aptos/ans_queries) - Query naming service data

---

## aggregator_v2

# aggregator_v2

Aggregator V2 is a specialized data structure in Aptos designed for high-performance concurrent counters that enable parallel transaction execution without conflicts. It leverages Aptos's Block-STM parallel execution engine to allow multiple transactions to increment or decrement the same counter simultaneously, dramatically improving throughput for applications with shared state.

## Overview

Traditional blockchain counters create transaction conflicts when multiple operations try to modify the same value concurrently. Aggregator V2 solves this by using commutative merge semantics, where operations can be applied in any order and combined at the end of block execution. This enables true parallelism for operations like tracking token supply, counting users, or maintaining statistics.

## Technical Implementation

Aggregator V2 uses a mathematical property called commutativity: addition and subtraction operations produce the same result regardless of execution order. The Block-STM engine tracks delta values during parallel execution and merges them atomically at commit time.

```move
module 0x1::token_counter {
    use aptos_framework::aggregator_v2::{Self, Aggregator};

    struct TokenStats has key {
        total_minted: Aggregator<u64>,
        total_burned: Aggregator<u64>,
        active_holders: Aggregator<u64>
    }

    public fun initialize(account: &signer) {
        move_to(account, TokenStats {
            total_minted: aggregator_v2::create_aggregator(0),
            total_burned: aggregator_v2::create_aggregator(0),
            active_holders: aggregator_v2::create_aggregator(0)
        });
    }

    public entry fun mint_tokens(amount: u64) acquires TokenStats {
        let stats = borrow_global_mut<TokenStats>(@0x1);
        aggregator_v2::add(&mut stats.total_minted, amount);
    }

    public entry fun burn_tokens(amount: u64) acquires TokenStats {
        let stats = borrow_global_mut<TokenStats>(@0x1);
        aggregator_v2::add(&mut stats.total_burned, amount);
    }

    public entry fun on_new_holder() acquires TokenStats {
        let stats = borrow_global_mut<TokenStats>(@0x1);
        aggregator_v2::add(&mut stats.active_holders, 1);
    }

    #[view]
    public fun get_total_minted(): u64 acquires TokenStats {
        let stats = borrow_global<TokenStats>(@0x1);
        aggregator_v2::read(&stats.total_minted)
    }

    #[view]
    public fun circulating_supply(): u64 acquires TokenStats {
        let stats = borrow_global<TokenStats>(@0x1);
        aggregator_v2::read(&stats.total_minted) - aggregator_v2::read(&stats.total_burned)
    }
}
```

## API Functions

```move
// Create new aggregator with initial value
aggregator_v2::create_aggregator<T>(initial_value: T): Aggregator<T>

// Add value (works for any numeric type)
aggregator_v2::add<T>(aggregator: &mut Aggregator<T>, value: T)

// Subtract value
aggregator_v2::sub<T>(aggregator: &mut Aggregator<T>, value: T)

// Read current value
aggregator_v2::read<T>(aggregator: &Aggregator<T>): T

// Try to subtract with bounds checking
aggregator_v2::try_sub<T>(aggregator: &mut Aggregator<T>, value: T): bool
```

## Real-World Use Cases

1. **Token Supply Tracking**: Track total minted and burned tokens across thousands of concurrent mint/burn transactions without creating bottlenecks or conflicts.

2. **User Statistics**: Maintain real-time counts of active users, daily transactions, or engagement metrics in high-traffic applications without serialization.

3. **DEX Volume Counters**: Aggregate trading volumes, swap counts, and liquidity metrics across parallel trading operations on decentralized exchanges.

4. **NFT Collection Stats**: Track total minted NFTs, active listings, and collection metrics as multiple users mint and trade simultaneously.

5. **Gaming Leaderboards**: Update player scores, achievement counts, and global statistics with high concurrency during peak gaming periods.

6. **Protocol Analytics**: Maintain real-time protocol metrics like total value locked, transaction counts, and fee accumulation without performance degradation.

## Performance Benefits

Without Aggregator V2, concurrent counter updates would create conflicts requiring sequential execution:

```move
// Traditional counter - causes conflicts
struct OldCounter has key {
    value: u64  // Every update conflicts with others
}

public fun increment() acquires OldCounter {
    let counter = borrow_global_mut<OldCounter>(@0x1);
    counter.value = counter.value + 1;  // Conflict!
}
```

With Aggregator V2, the same operations execute in parallel:

```move
// Parallel counter - no conflicts
struct NewCounter has key {
    value: Aggregator<u64>  // Parallel updates merge
}

public fun increment() acquires NewCounter {
    let counter = borrow_global_mut<NewCounter>(@0x1);
    aggregator_v2::add(&mut counter.value, 1);  // Parallelizes!
}
```

Benchmark results show 10-100x throughput improvements for counter-heavy workloads.

## Best Practices

**Use for Shared State**: Apply Aggregator V2 to any counter or accumulator that multiple transactions will modify concurrently.

**Combine with Regular Fields**: Mix aggregators with normal fields in the same struct for optimal performance:

```move
struct MixedStats has key {
    total_count: Aggregator<u64>,  // Parallel updates
    last_updated: u64,             // Sequential field
    admin: address                 // Sequential field
}
```

**Read Sparingly in Transactions**: Reading aggregator values during transaction execution may reduce parallelism. Prefer reads in view functions.

**Batch Operations**: When possible, batch multiple small updates into larger operations to reduce overhead.

**Consider Overflow**: While aggregators support large numbers, implement checks for meaningful limits based on your application logic.

**Monitor Performance**: Use Aptos performance metrics to verify that aggregators are providing expected parallelism benefits.

## Limitations and Considerations

- Aggregators only support commutative operations (addition, subtraction)
- Cannot use aggregators for operations requiring specific ordering
- Reading aggregator values in transaction execution may impact parallelism
- Not suitable for operations requiring immediate consistency checks
- Best suited for statistics and metrics rather than critical balance tracking

## Migration from V1

If you're using the older Aggregator V1 API, migrate to V2 for improved performance:

```move
// V1 (deprecated)
use aptos_framework::aggregator;
let agg = aggregator::create(100); // With max limit

// V2 (recommended)
use aptos_framework::aggregator_v2;
let agg = aggregator_v2::create_aggregator(0); // No max limit needed
```

## Related Concepts

- [Block-STM](https://medium.com/aptoslabs/block-stm-how-we-execute-over-160k-transactions-per-second-on-the-aptos-blockchain-3b003657e4ba) - Parallel execution engine
- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Managing shared state
- [Testing](https://www.dwellir.com/docs/aptos/testing) - Test parallel execution scenarios
- [View Functions](https://www.dwellir.com/docs/aptos/view_functions) - Read aggregator values efficiently

---

## ans_queries

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# ans_queries

Aptos Name Service (ANS) provides human-readable names for Aptos addresses, similar to DNS for the internet. The GraphQL API enables efficient querying of ANS registrations, allowing applications to resolve names to addresses, lookup reverse mappings, check expiration dates, and manage domain portfolios programmatically.

## Overview

ANS transforms complex hexadecimal addresses like `0x1a2b3c...` into memorable names like `alice.apt`, significantly improving user experience. The GraphQL indexer provides indexed access to ANS data, enabling fast lookups for wallet displays, payment systems, social features, and any application needing human-readable identifiers.

## Core Query Patterns

### Resolve Name to Address

```graphql
query ResolveName($name: String!) {
  ans_lookup(where: { name: { _eq: $name } }) {
    name
    address
    expiration_timestamp
    registered_at
    owner
  }
}
```

### Reverse Lookup (Address to Names)

```graphql
query AddressToNames($address: String!) {
  ans_lookup(
    where: { address: { _eq: $address } },
    order_by: { registered_at: desc }
  ) {
    name
    expiration_timestamp
    is_primary
  }
}
```

### Check Name Availability

```graphql
query CheckAvailability($name: String!) {
  ans_lookup(
    where: {
      name: { _eq: $name },
      expiration_timestamp: { _gt: "now()" }
    }
  ) {
    name
    owner
  }
}
```

### Get Primary Name

```graphql
query GetPrimaryName($address: String!) {
  ans_lookup(
    where: {
      address: { _eq: $address },
      is_primary: { _eq: true }
    },
    limit: 1
  ) {
    name
    expiration_timestamp
  }
}
```

### Search Names by Pattern

```graphql
query SearchNames($pattern: String!, $limit: Int!) {
  ans_lookup(
    where: { name: { _like: $pattern } },
    order_by: { registered_at: desc },
    limit: $limit
  ) {
    name
    address
    owner
    registered_at
  }
}
```

### Expiring Names

```graphql
query ExpiringNames($days: Int!) {
  ans_lookup(
    where: {
      expiration_timestamp: {
        _gte: "now()",
        _lte: "now() + ${days} days"
      }
    },
    order_by: { expiration_timestamp: asc }
  ) {
    name
    address
    expiration_timestamp
  }
}
```

## Real-World Use Cases

1. **Wallet Applications**: Display user-friendly names instead of addresses in transaction histories, contact lists, and payment interfaces for improved UX.

2. **Payment Systems**: Allow users to send payments to names like "alice.apt" instead of copying long addresses, reducing errors and improving accessibility.

3. **Social Platforms**: Enable username-based social features where users can follow, message, or interact with others using memorable names.

4. **Domain Marketplaces**: Build platforms for buying, selling, and trading ANS domains with search, filtering, and expiration monitoring.

5. **Portfolio Management**: Track domain portfolios, monitor expiration dates, and manage renewal workflows for users with multiple names.

6. **Identity Verification**: Use ANS as a lightweight identity system where verified names provide reputation and trust signals.

## Best Practices

**Cache Resolved Names**: ANS data changes infrequently - implement caching with appropriate TTLs to reduce API calls.

**Handle Non-Existent Names**: Always check for null/empty results when resolving names and provide clear user feedback.

**Validate Name Format**: Implement client-side name validation (format, length, allowed characters) before querying.

**Check Expiration**: Always verify expiration\_timestamp to ensure names are still active before relying on them.

**Support Both Directions**: Implement both name-to-address and address-to-name lookups for complete functionality.

**Prioritize Primary Names**: When an address owns multiple names, prefer displaying the primary name for consistency.

**Batch Lookups**: When resolving multiple names, batch them into single GraphQL queries for efficiency.

## TypeScript Integration

```typescript
import { ApolloClient, gql } from "@apollo/client";

const client = new ApolloClient({
  uri: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql"
});

async function resolveName(name: string): Promise<string | null> {
  const { data } = await client.query({
    query: gql`
      query ResolveName($name: String!) {
        ans_lookup(where: { name: { _eq: $name } }) {
          address
          expiration_timestamp
        }
      }
    `,
    variables: { name }
  });

  const result = data.ans_lookup[0];
  if (!result) return null;

  const now = Date.now();
  const expiration = new Date(result.expiration_timestamp).getTime();

  return expiration > now ? result.address : null;
}

async function getPrimaryName(address: string): Promise<string | null> {
  const { data } = await client.query({
    query: gql`
      query GetPrimaryName($address: String!) {
        ans_lookup(
          where: {
            address: { _eq: $address },
            is_primary: { _eq: true }
          },
          limit: 1
        ) {
          name
          expiration_timestamp
        }
      }
    `,
    variables: { address }
  });

  const result = data.ans_lookup[0];
  if (!result) return null;

  const now = Date.now();
  const expiration = new Date(result.expiration_timestamp).getTime();

  return expiration > now ? result.name : null;
}
```

## Advanced Queries

### Domain Portfolio Analysis

```graphql
query PortfolioStats($owner: String!) {
  active: ans_lookup_aggregate(
    where: {
      owner: { _eq: $owner },
      expiration_timestamp: { _gt: "now()" }
    }
  ) {
    aggregate { count }
  }

  expiring_soon: ans_lookup_aggregate(
    where: {
      owner: { _eq: $owner },
      expiration_timestamp: {
        _gt: "now()",
        _lte: "now() + 30 days"
      }
    }
  ) {
    aggregate { count }
  }

  domains: ans_lookup(
    where: { owner: { _eq: $owner } },
    order_by: { expiration_timestamp: asc }
  ) {
    name
    address
    expiration_timestamp
    registered_at
  }
}
```

### Marketplace Trending Names

```graphql
query TrendingNames($hours: Int!) {
  ans_lookup(
    where: {
      registered_at: { _gte: "now() - ${hours} hours" }
    },
    order_by: { registered_at: desc },
    limit: 50
  ) {
    name
    address
    owner
    registered_at
  }
}
```

## Common Patterns

```typescript
// Display name with fallback to address
function displayName(address: string, ansName?: string | null): string {
  if (ansName) return ansName;
  return `${address.substring(0, 6)}...${address.substring(address.length - 4)}`;
}

// Validate name format
function isValidANSName(name: string): boolean {
  return /^[a-z0-9-]{1,63}\.apt$/.test(name);
}

// Check if name is expired
function isExpired(expirationTimestamp: string): boolean {
  return new Date(expirationTimestamp).getTime() < Date.now();
}
```

## Related Concepts

- [GraphQL Overview](https://www.dwellir.com/docs/aptos/graphql/overview) - GraphQL indexer introduction
- [Aggregations](https://www.dwellir.com/docs/aptos/aggregations) - Aggregate ANS statistics
- [User Transactions](https://www.dwellir.com/docs/aptos/user_transactions) - Track ANS registrations
- [Subscriptions](https://www.dwellir.com/docs/aptos/subscriptions) - Real-time ANS updates

---

## Aptos API Authentication

# Aptos API Authentication

Every Dwellir Aptos endpoint authenticates with the **same API key** from your
[dashboard](https://dashboard.dwellir.com). There is no separate streaming
credential and no per-service token to provision.

What changes between services is *where* the key goes.

| Service                   | Where the key goes               |
| ------------------------- | -------------------------------- |
| REST (`/v1`)              | URL path segment                 |
| Indexer GraphQL           | URL path segment                 |
| Transaction Stream (gRPC) | `x-api-key` gRPC metadata header |

## REST and GraphQL

Both take the key as a path segment before `/v1`:

```bash
curl -X GET https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1 \
  -H "Accept: application/json"
```

```bash
curl -X POST https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"query { ledger_infos(limit: 1) { chain_id version } }"}'
```

## Transaction Stream (gRPC)

The gRPC stream takes the key as metadata, matching how our
[Sui gRPC endpoints](https://www.dwellir.com/docs/sui/grpc-overview#authentication) work. Do **not**
append it to the endpoint as a path segment.

```
x-api-key: YOUR_API_KEY
```

TypeScript
Python
Go

```typescript
import { credentials, Metadata } from '@grpc/grpc-js';

const metadata = new Metadata();
metadata.add('x-api-key', process.env.DWELLIR_API_KEY);

const client = new RawDataClient(
  process.env.DWELLIR_APTOS_STREAM_ENDPOINT,
  credentials.createSsl()
);

const stream = client.GetTransactions(request, metadata);
```

```python
import grpc

channel = grpc.secure_channel(endpoint, grpc.ssl_channel_credentials())
stub = raw_data_pb2_grpc.RawDataStub(channel)

metadata = [('x-api-key', api_key)]
for response in stub.GetTransactions(request, metadata=metadata):
    for tx in response.transactions:
        handle(tx)
```

```go
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)

stream, err := client.GetTransactions(ctx, req)
```

Earlier revisions of these docs showed `authorization: Bearer <key>` and an mTLS
option. Neither applies to Dwellir. The Bearer form belongs to Aptos Labs' hosted
Transaction Stream, and we do not offer client-certificate authentication on any
endpoint. Use `x-api-key`.

The endpoint hostname and header are confirmed in writing when your account is
provisioned for the stream, which is still in
[early access](https://www.dwellir.com/docs/aptos/streaming/overview).

## Handling Auth Failures

A rejected key surfaces as `UNAUTHENTICATED` (gRPC status 16) on the stream, or
`401` on REST and GraphQL:

```typescript
import { status } from '@grpc/grpc-js';

stream.on('error', (error) => {
  if (error.code === status.UNAUTHENTICATED) {
    // Key is missing, wrong, or not provisioned for the stream.
    // Do not retry with backoff - this will not resolve on its own.
    return alertOperator(error.details);
  }

  scheduleReconnect();
});
```

Authentication failures are not transient. Retrying an invalid key burns your rate
limit and delays the alert, so keep it off the reconnect path.

Do not confuse it with `RESOURCE_EXHAUSTED` (status 8), which means rate limiting
rather than a bad key — and on Dwellir, rate limits are scoped
[per account, not per key](https://www.dwellir.com/docs/getting-started/rate-limits#scope-per-account-not-per-key).

## Key Handling

- **Keep keys server-side.** A key embedded in a browser or mobile bundle is
  public. Proxy through a backend you control.
- **Use environment variables or a secrets manager**, never checked-in config.
- **Use separate keys per environment** so a staging mistake cannot exhaust
  production budget — though note that rate limits pool per account, so separate
  keys on one account still share a limit.
- **Rotate through the dashboard** and set per-key usage quotas at
  [dashboard.dwellir.com/api-keys](https://dashboard.dwellir.com/api-keys).
- **Never log the key**, including in gRPC metadata dumps while debugging.

## Related Guides

- [Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) — service definition and metering
- [Real-Time Streaming](https://www.dwellir.com/docs/aptos/real_time) — tailing the head of chain
- [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits) — plan limits and per-account scope
- [Sui gRPC Authentication](https://www.dwellir.com/docs/sui/grpc-overview#authentication) — the same header on our Sui endpoints

---

## blocks_by_height

# blocks_by_height

## Overview

Fetch a block by its block height together with block metadata, and optionally expand the block into the transactions it contains. This is the right endpoint when you already know the block you want and need to anchor application logic to block boundaries instead of individual transaction hashes.

## Endpoint

`GET /v1/blocks/by_height/{block_height}`

`block_height` identifies the consensus block, not a single ledger version. One block can include multiple transactions, so this endpoint is useful for explorers, replay jobs, and monitoring systems that checkpoint work at block level.

## Request Parameters

- `block_height` (`string, required`): Path parameter: Aptos block height to retrieve
- `with_transactions` (`boolean, optional`): Query parameter: Include full transaction objects instead of block metadata alone

## Request Example

```bash
# Get block metadata only
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/blocks/by_height/1000000" \
      -H "Accept: application/json"

    # Get block with all transactions
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/blocks/by_height/1000000?with_transactions=true" \
      -H "Accept: application/json"
```

## Response Fields

- `result` (`OBJECT, required`): With `with_transactions=false`, the response stays compact and is best for checkpointing or timeline views: ```json { "block_height": "1000000", "block_hash": "0xd8f4f8cb...", "first_version": "10240841", "last_version": "10240863", "block_timestamp": "1661961900602338", "transactions": null } ``` When `with_transactions=true`, the response also includes the committed transactions inside that block. That is useful for replay or block explorer detail pages, but it can grow large on busy blocks.

## Successful Response

```json
{
  "block_height": "1000000",
  "block_hash": "0xd8f4f8cb...",
  "first_version": "10240841",
  "last_version": "10240863",
  "block_timestamp": "1661961900602338",
  "transactions": null
}
```

## Response Shape

With `with_transactions=false`, the response stays compact and is best for checkpointing or timeline views:

```json
{
  "block_height": "1000000",
  "block_hash": "0xd8f4f8cb...",
  "first_version": "10240841",
  "last_version": "10240863",
  "block_timestamp": "1661961900602338",
  "transactions": null
}
```

When `with_transactions=true`, the response also includes the committed transactions inside that block. That is useful for replay or block explorer detail pages, but it can grow large on busy blocks.

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Get block metadata only
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/blocks/by_height/1000000" \
  -H "Accept: application/json"

# Get block with all transactions
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/blocks/by_height/1000000?with_transactions=true" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Metadata only
block = client.block_by_height(1_000_000, with_transactions=False)
print(f"Block {block['block_height']}: versions {block['first_version']}-{block['last_version']}")

# With transactions
block = client.block_by_height(1_000_000, with_transactions=True)
for txn in block.get("transactions", []):
    print(f"  Version {txn['version']}: {txn['vm_status']}")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Get block with transactions
const block = await aptos.getBlockByHeight({
  blockHeight: 1_000_000n,
  options: { withTransactions: true }
});
console.log(`Block ${block.block_height}: ${block.transactions?.length} txns`);
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

// Get block with transactions
let block = client.get_block_by_height(1_000_000, true).await?;
println!("Block hash: {}", block.inner().block_hash);
println!("Versions: {}-{}", block.inner().first_version, block.inner().last_version);
```

## When to Enable `with_transactions`

- Set it to `false` when you only need block boundaries, timestamps, or version ranges.
- Set it to `true` when your worker will immediately process the block's transactions and you want to avoid extra follow-up lookups.
- Prefer metadata-only reads for polling or checkpoint loops, then expand only the blocks you actually need to inspect in detail.

## Practical Guidance

- Store both `block_height` and the `first_version`/`last_version` range if you plan to resume block-based indexing later. Read `block_timestamp` from the metadata response rather than assuming a generic `timestamp` field.
- Busy blocks can return large payloads, so avoid defaulting to `with_transactions=true` in lightweight monitoring jobs.
- If your UI deep-links into one transaction from the block, pair this endpoint with [`transactions_by_hash`](https://www.dwellir.com/docs/aptos/transactions_by_hash) for the detailed drill-down.
- Treat block height and ledger version as different coordinates. A version points to one transaction; a block height points to a grouped execution boundary.

## Related Endpoints

- [accounts\_transactions](https://www.dwellir.com/docs/aptos/accounts_transactions) for sender-scoped history
- [transactions\_by\_hash](https://www.dwellir.com/docs/aptos/transactions_by_hash) for one known transaction

---

## blocks_by_version

# blocks_by_version

## Overview

Fetch the block that contains a given ledger version. This endpoint is useful when you have a transaction version and need to understand its block context, including block metadata, timestamp, and related transactions.

## Endpoint

`GET /v1/blocks/by_version/{version}`

## Request

### Path Parameters

| Name    | Type   | Required | Description                          |
| ------- | ------ | -------- | ------------------------------------ |
| version | string | Yes      | Ledger version (transaction version) |

### Query Parameters

| Name               | Type    | Required | Description                               |
| ------------------ | ------- | -------- | ----------------------------------------- |
| with\_transactions | boolean | No       | Include full transaction data in response |

## Response

### Success Response (200)

Returns a block object containing:

```json
{
  "block_height": "1000000",
  "block_hash": "0x...",
  "block_timestamp": "1234567890",
  "first_version": "123456700",
  "last_version": "123456789",
  "transactions": [...]
}
```

When `with_transactions=true`, the transactions array contains complete transaction objects. Without this parameter, only block metadata is returned.

### Error Responses

| Status | Error Code          | Description               |
| ------ | ------------------- | ------------------------- |
| 400    | invalid\_input      | Invalid version format    |
| 404    | version\_not\_found | Version doesn't exist yet |
| 500    | internal\_error     | Server error              |

## Code Examples

```bash
curl -X GET https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/blocks/by_version/123456789?with_transactions=true \
  -H "Accept: application/json"
```

## Use Cases

This endpoint serves several important purposes in blockchain development:

1. **Transaction Context Discovery**: Given a specific transaction version, retrieve its block context to understand when and how it was processed, including block timestamp and proposer information.

2. **Block Explorer Implementation**: Build block explorers that allow users to navigate from individual transactions to their containing blocks, showing all transactions processed together.

3. **Temporal Analysis**: Analyze transaction ordering and timing within blocks to understand MEV opportunities, transaction dependencies, or validator behavior.

4. **Event Correlation**: When investigating events across multiple transactions, use this endpoint to group related transactions that were executed in the same block.

5. **Audit Trail Construction**: Create comprehensive audit trails by linking transactions to their block context, providing immutable timestamps and ordering guarantees.

6. **State Snapshot Coordination**: Coordinate state snapshots across multiple accounts or resources by identifying block boundaries that represent consistent global state.

## Best Practices

**Version vs Height**: This endpoint uses transaction version (ledger version), not block height. Transaction versions are sequential across all transactions, while block heights increment per block. Use `blocks/by_height` if you have a block height instead.

**Pagination Strategy**: When `with_transactions=true`, large blocks can return megabytes of data. If you need to process many blocks, consider fetching metadata first, then selectively fetching transaction details only when needed.

**Caching**: Block data is immutable once finalized. Implement aggressive caching for historical blocks (older than 100 versions from chain head) to minimize API load.

**Version Boundaries**: Each block contains a range of versions from `first_version` to `last_version`. To process all transactions in a block, iterate through this range using individual transaction queries if needed.

## Performance Considerations

Queries without `with_transactions` are fast and lightweight (typically under 50ms). Including full transaction data can increase response time to 200-500ms for blocks with many transactions, depending on transaction complexity and payload sizes. The response size can range from a few KB (metadata only) to several MB (large blocks with full transaction data).

For high-throughput applications processing many blocks sequentially, consider using the transaction streaming API instead of polling individual blocks.

---

## Building Aptos Stream Processors

The Aptos Transaction Stream is not generally available. Email
<support@dwellir.com> to join the early-access list.

# Building Aptos Stream Processors

A processor subscribes to the Transaction Stream, decodes the transactions it
cares about, and writes them into your own schema. This page covers the
architecture; see the
[Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) for the service
definition and [Real-Time Streaming](https://www.dwellir.com/docs/aptos/real_time) for the connection and
reconnect mechanics.

## The Processing Loop

The unit of work is a `TransactionsResponse` — a batch — not a transaction. Build
the loop around the batch, because the batch is also the checkpoint boundary and
the billing unit.

```typescript
class AptosStreamProcessor {
  async handleBatch(response) {
    // Nothing matched the filter in this range, but progress still advanced.
    if (response.transactions.length === 0) {
      return this.checkpoint.observe(response);
    }

    const records = [];
    for (const tx of response.transactions) {
      const decoded = this.decode(tx);
      if (decoded) records.push(decoded);
    }

    // One transactional write per batch, then checkpoint.
    await this.db.transaction(async (trx) => {
      await trx.bulkUpsert('transactions', records);
      await trx.upsert('stream_checkpoints', {
        name: 'aptos',
        last_version: response.processed_range.last_version,
      });
    });
  }
}
```

Writing the records and the checkpoint in the **same database transaction** is
what makes restarts safe. Split them and a crash between the two either loses
versions or reprocesses them.

A filtered stream sends messages with no transactions when nothing in a version
range matched. They still carry `processed_range` and they are still metered.
Treat an empty batch as a progress update, not as an error or an idle stream.

## Filter Server-Side First

Anything you can express as a `BooleanTransactionFilter` should go in the request
rather than in `shouldProcess()`. The filter runs on the node, before delivery and
before metering, so server-side filtering reduces your bill while client-side
filtering does not.

```typescript
// Prefer this...
const request = {
  transaction_filter: {
    api_filter: {
      user_transaction_filter: {
        payload_filter: {
          entry_function_filter: { address: '0x1', module_name: 'coin' },
        },
      },
    },
  },
};

// ...over receiving everything and discarding it in the handler.
```

Client-side filtering still has a place for conditions the filter cannot express —
decoded field values, cross-transaction state, or thresholds computed at runtime.

## Decoding Events

Events hang off the transaction payload. `Event.type_str` carries the fully
qualified Move struct tag, and `data` is a JSON string:

```typescript
function decodeEvents(tx) {
  const events = tx.user?.events ?? tx.block_metadata?.events ?? [];

  return events.flatMap((event) => {
    const data = JSON.parse(event.data);

    switch (event.type_str) {
      case '0x1::coin::WithdrawEvent':
        return [{
          kind: 'coin_withdraw',
          amount: BigInt(data.amount),
          account: event.key?.account_address,
          sequence: BigInt(event.sequence_number),
          version: BigInt(tx.version),
        }];

      case '0x1::coin::DepositEvent':
        return [{
          kind: 'coin_deposit',
          amount: BigInt(data.amount),
          account: event.key?.account_address,
          sequence: BigInt(event.sequence_number),
          version: BigInt(tx.version),
        }];

      default:
        return [];
    }
  });
}
```

Numeric fields annotated `jstype = JS_STRING` arrive as strings in most JavaScript
stubs. Parse them with `BigInt` rather than `Number` — Aptos amounts in Octas
exceed `Number.MAX_SAFE_INTEGER`.

## Idempotent Writes

A reconnect can redeliver versions you already processed, so every write must be
safe to repeat. Key on `version` — it is unique and monotonic across the chain:

```sql
INSERT INTO coin_transfers (version, event_index, sender, amount)
VALUES ($1, $2, $3, $4)
ON CONFLICT (version, event_index) DO NOTHING;
```

Derived aggregates need the same care. Recompute them from the stored rows, or
guard the increment with the version, rather than blindly adding on each delivery.

## Isolating Failures

A malformed record should not stall the stream. Route repeated failures to a dead
letter table and keep the checkpoint moving:

```typescript
async function processWithIsolation(tx) {
  try {
    await processTransaction(tx);
  } catch (error) {
    await deadLetter.insert({
      version: tx.version,
      error: error.message,
      received_at: new Date(),
    });
    // Do not rethrow - one bad transaction must not block the batch.
  }
}
```

Distinguish the two failure classes. A decode error is specific to one transaction
and belongs in the dead letter table. A database outage affects every transaction,
and retrying the batch is correct — swallowing it silently loses data.

Aptos reaches BFT finality before a transaction enters the stream. Versions are
never revised, so processors need no reorg or rollback logic. Do not port
confirmation-depth patterns from Ethereum indexers.

## Scaling the Write Path

The stream is ordered and single-connection, so parallelism belongs downstream of
the reader, not in extra subscriptions.

- **Keep one reader.** Opening several tails of the same range multiplies your
  metered messages without adding throughput.
- **Parallelize by partition.** Shard decoded records across workers by account or
  event type, then checkpoint only once every shard has committed its slice.
- **Batch database writes** to whole batches rather than per transaction.
- **Flush checkpoints on an interval**, not on every message. Checkpoint writes are
  small and frequent, and they dominate write load if left unbatched.

## Monitoring

| Metric                | What it tells you                                           |
| --------------------- | ----------------------------------------------------------- |
| Version lag           | Head version minus checkpoint. The headline health signal.  |
| Batch processing time | Rising time means you will fall behind before lag shows it. |
| Dead letter rate      | A spike usually means a schema change upstream.             |
| Messages per second   | Compare against your plan's limit and your Sui usage.       |

## Related Guides

- [Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) — service definition and metering
- [Real-Time Streaming](https://www.dwellir.com/docs/aptos/real_time) — connection and reconnect mechanics
- [Historical Replay](https://www.dwellir.com/docs/aptos/historical_replay) — backfilling a new processor
- [Authentication](https://www.dwellir.com/docs/aptos/authentication) — API key handling

---

## entry_functions

# entry_functions

## Overview

Entry functions are the primary mechanism for executing Move code via transactions on Aptos. These special functions serve as transaction entry points, allowing external accounts to trigger on-chain logic execution.

## Technical Details

Entry functions are declared with the `public entry` visibility modifier in Move modules:

```move
public entry fun transfer(from: &signer, to: address, amount: u64) {
    // Function implementation
}
```

**Key Characteristics**:

- Must be marked with both `public` and `entry` keywords
- Can be called directly from transactions
- Cannot return values (void return type)
- Can modify blockchain state
- Execute with the transaction sender's authority
- Support generic type parameters

## How Entry Functions Work

When a transaction calls an entry function:

1. The Move VM loads the module containing the function
2. Arguments are BCS-deserialized from transaction payload
3. The function executes with sender's signer capability
4. State changes are committed if execution succeeds
5. Events are emitted to the blockchain
6. Gas is consumed based on computational cost

Entry functions form the external API of Move modules, bridging off-chain applications with on-chain logic.

## Practical Examples

**Simple Transfer:**

```move
public entry fun simple_transfer(sender: &signer, recipient: address, amount: u64) {
    coin::transfer<AptosCoin>(sender, recipient, amount);
}
```

**With Type Parameters:**

```move
public entry fun swap<CoinTypeA, CoinTypeB>(
    sender: &signer,
    amount_in: u64,
    min_amount_out: u64
) {
    // DEX swap implementation
}
```

**Multiple Operations:**

```move
public entry fun batch_mint(admin: &signer, recipients: vector<address>, amounts: vector<u64>) {
    let len = vector::length(&recipients);
    let i = 0;
    while (i < len) {
        let recipient = *vector::borrow(&recipients, i);
        let amount = *vector::borrow(&amounts, i);
        mint_to(admin, recipient, amount);
        i = i + 1;
    };
}
```

## Use Cases

Entry functions power diverse blockchain applications:

1. **Token Operations**: Transfers, minting, burning, and approvals for fungible and non-fungible tokens.

2. **DeFi Protocols**: Swaps, liquidity provision, staking, and yield farming operations.

3. **NFT Marketplaces**: Listing, purchasing, bidding, and collection management.

4. **Gaming**: Character creation, item crafting, battle execution, and reward distribution.

5. **Governance**: Proposal submission, voting, and execution of governance decisions.

6. **Identity**: Account creation, key rotation, and permission management.

## Best Practices

**Input Validation**: Always validate inputs within entry functions to prevent invalid state transitions. Check address validity, amount ranges, and permission requirements explicitly.

**Avoid Write Conflicts**: Under Block-STM parallel execution, minimize conflicts by:

- Reading shared resources early in execution
- Writing to unique per-account resources when possible
- Using fine-grained resource structures instead of global state
- Leveraging Aggregator V2 for concurrent counters

**Gas Efficiency**: Keep entry functions focused and delegate complex logic to internal helper functions. This improves code organization and allows better gas optimization.

**Error Handling**: Use descriptive abort codes and messages to help developers debug failed transactions:

```move
const EINSUFFICIENT_BALANCE: u64 = 1;
const EINVALID_RECIPIENT: u64 = 2;

public entry fun safe_transfer(sender: &signer, to: address, amount: u64) {
    assert!(to != @0x0, EINVALID_RECIPIENT);
    assert!(coin::balance<AptosCoin>(signer::address_of(sender)) >= amount, EINSUFFICIENT_BALANCE);
    coin::transfer<AptosCoin>(sender, to, amount);
}
```

**Signer Requirement**: Only include `&signer` parameters for accounts that must authorize the transaction. Extra signer parameters complicate multi-signature scenarios unnecessarily.

**Event Emission**: Emit events for significant state changes to enable off-chain indexing and monitoring:

```move
event::emit(TransferEvent {
    from: signer::address_of(sender),
    to: recipient,
    amount
});
```

## Common Patterns

**Admin Functions**: Restrict privileged operations with capability checks:

```move
public entry fun admin_mint(admin: &signer, to: address, amount: u64) acquires AdminCap {
    let admin_addr = signer::address_of(admin);
    assert!(exists<AdminCap>(admin_addr), ENOT_ADMIN);
    // Mint logic
}
```

**Batch Operations**: Process multiple operations in one transaction for efficiency:

```move
public entry fun batch_transfer(sender: &signer, recipients: vector<address>, amounts: vector<u64>) {
    let len = vector::length(&recipients);
    let i = 0;
    while (i < len) {
        coin::transfer<AptosCoin>(sender, *vector::borrow(&recipients, i), *vector::borrow(&amounts, i));
        i = i + 1;
    };
}
```

**Resource Initialization**: Create and move resources to accounts:

```move
public entry fun initialize_account(account: &signer) {
    move_to(account, AccountData {
        balance: 0,
        nonce: 0
    });
}
```

## Anti-Patterns to Avoid

- **Returning Values**: Entry functions cannot return values. Use view functions for read operations.
- **Excessive Computation**: Long-running computations cause high gas costs and potential timeouts.
- **Global Locks**: Accessing single global resources creates bottlenecks under Block-STM.
- **Unbounded Loops**: Loops over unbounded vectors risk gas exhaustion.

## Related Concepts

- **View Functions**: Read-only functions for querying state without gas costs
- **Script Functions**: Legacy transaction entry points, now superseded by entry functions
- **Public Functions**: Module functions callable by other modules but not directly via transactions
- **Inline Functions**: Private helper functions for code organization

---

## estimate_gas_price

# estimate_gas_price

## Overview

Retrieve current gas price estimates for Aptos transactions. This endpoint provides three tiers of gas pricing to help applications choose appropriate fees based on urgency: prioritized (fast), standard, and deprioritized (economy). Gas prices are measured in octas per gas unit (1 APT = 100,000,000 octas).

## Endpoint

`GET /v1/estimate_gas_price`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/estimate_gas_price" \
      -H "Accept: application/json"
```

## Response Fields

- `prioritized_gas_estimate` (`integer, required`): Higher gas price suggestion for urgent transactions
- `gas_estimate` (`integer, required`): Standard gas price suggestion for normal transaction flow
- `deprioritized_gas_estimate` (`integer, required`): Lower gas price suggestion for cost-sensitive, non-urgent transactions

## Successful Response

```json
{
  "prioritized_gas_estimate": 150,
  "gas_estimate": 100,
  "deprioritized_gas_estimate": 100
}
```

## Error Responses

### Error 1

- Code: `internal_error`
- Description: Server error estimating gas

### Error 2

- Code: `service_unavailable`
- Description: Gas estimation temporarily unavailable

## Code Examples

cURL
Python
TypeScript
Rust

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/estimate_gas_price" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
gas = client.estimate_gas_price()

print(f"Prioritized: {gas['prioritized_gas_estimate']} octas/unit")
print(f"Standard:    {gas['gas_estimate']} octas/unit")
print(f"Economy:     {gas['deprioritized_gas_estimate']} octas/unit")

# Use in transaction building
gas_unit_price = int(gas["gas_estimate"])
max_gas_amount = 2000  # typical for simple transfers
max_cost_octas = gas_unit_price * max_gas_amount
max_cost_apt = max_cost_octas / 100_000_000
print(f"Max transaction cost: {max_cost_apt} APT")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// The SDK handles gas estimation internally, but you can also query directly
const response = await fetch(
  "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/estimate_gas_price",
  { headers: { "Accept": "application/json" } }
);
const estimates = await response.json();
console.log(`Prioritized: ${estimates.prioritized_gas_estimate} octas`);
console.log(`Standard:    ${estimates.gas_estimate} octas`);
console.log(`Economy:     ${estimates.deprioritized_gas_estimate} octas`);
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let gas = client.estimate_gas_price().await?;

println!("Standard gas estimate: {} octas/unit", gas.inner().gas_estimate);
println!("Prioritized: {} octas/unit", gas.inner().prioritized_gas_estimate);
```

## Understanding Aptos Gas

Aptos gas works differently from EVM chains:

| Concept        | Description                                                                      |
| -------------- | -------------------------------------------------------------------------------- |
| Gas Unit Price | Price per unit of gas in octas (this endpoint provides estimates)                |
| Gas Used       | Actual gas units consumed during execution (varies by operation)                 |
| Max Gas Amount | Maximum gas units the sender is willing to pay (set during transaction building) |
| Total Cost     | `gas_used * gas_unit_price` in octas (charged after execution)                   |

**Typical gas usage by operation:**

| Operation                     | Approximate Gas Units |
| ----------------------------- | --------------------- |
| Simple APT transfer           | 10-20                 |
| Token transfer                | 20-50                 |
| Smart contract call (simple)  | 50-200                |
| Smart contract call (complex) | 200-5,000             |
| Module deployment             | 1,000-50,000          |

At 100 octas per gas unit, a simple APT transfer costs approximately 0.000002 APT (2,000 octas), making Aptos one of the most cost-effective layer-1 blockchains.

## Use Cases

1. **Dynamic Transaction Fee Setting**: Automatically adjust transaction gas prices based on current network conditions rather than using hardcoded values, ensuring reliable execution without overpaying.

2. **User Experience Optimization**: Offer users multiple speed/cost options (fast/normal/economy) by exposing the three gas tier estimates, similar to modern blockchain wallets.

3. **Batch Operation Cost Planning**: Estimate total costs for batch operations by multiplying gas estimates by expected gas consumption per transaction, helping optimize batching strategies.

4. **Gas Price Monitoring**: Track gas price trends over time to identify network congestion patterns and schedule non-urgent operations during low-fee periods.

5. **Multi-Chain Cost Comparison**: Compare Aptos gas costs with other blockchains to provide users with informed decisions about which chain to use for specific operations.

6. **Smart Contract Budgeting**: Applications with gas sponsorship or limited budgets can use deprioritized estimates to maximize transaction throughput within budget constraints.

## Best Practices

**Query Frequency**: Gas prices on Aptos are relatively stable compared to EVM chains due to the Block-STM parallel execution model. Query every 30-60 seconds for normal applications, or more frequently during known high-traffic events.

**Price Selection Logic**: For user-initiated transactions, use the standard estimate. For urgent operations like liquidations or time-sensitive trades, use prioritized. For background tasks or gas-sponsored operations, use deprioritized.

**Safety Margins**: Add a 10-20% buffer to estimates to account for price fluctuations between estimation and submission, especially for prioritized transactions during volatile periods.

**Transaction Expiration**: Set appropriate expiration timestamps (typically 60-120 seconds) that match your gas tier choice. Prioritized transactions should have shorter expirations, while deprioritized can be longer.

**Error Recovery**: If gas estimation fails (500/503 errors), fall back to conservative hardcoded values. For mainnet, safe fallback values are: prioritized=200, standard=100, deprioritized=100 octas per gas unit.

**Combining with Simulation**: For precise cost estimates, first call `estimate_gas_price` for the unit price, then simulate the transaction via `POST /v1/transactions/simulate` to get the actual gas units consumed. Multiply the two for the total cost.

## Performance Considerations

This endpoint is extremely lightweight and typically responds in under 20ms. The estimates are calculated based on recent block gas usage and mempool analysis, updated every block (approximately every 4 seconds on mainnet).

Gas estimates reflect the minimum gas unit price needed for inclusion, but actual transaction costs depend on gas consumption (`gas_used * gas_unit_price`). A simple transfer might consume 10-20 gas units, while complex smart contract interactions can consume thousands.

The response is under 200 bytes, making it suitable for frequent polling even on bandwidth-constrained connections.

## Related Endpoints

- `/v1/transactions/simulate` - Simulate a transaction to get exact gas usage
- `/v1/transactions` - Submit transactions using the estimated gas price
- `/v1` - Get ledger info (useful for setting expiration timestamps)
- `/v1/transactions/encode_submission` - Encode a transaction with gas parameters

---

## events

# events

## Overview

Events in Move provide a mechanism for smart contracts to emit structured notifications about state changes to off-chain systems. Events enable indexers, applications, and users to track on-chain activities without continuously polling resources.

## Technical Details

Events are defined as Move structs and emitted using the `event::emit` function:

```move
use aptos_framework::event;

struct TransferEvent has drop, store {
    from: address,
    to: address,
    amount: u64
}

public entry fun transfer_with_event(from: &signer, to: address, amount: u64) {
    // Transfer logic here
    event::emit(TransferEvent {
        from: signer::address_of(from),
        to,
        amount
    });
}
```

**Event Properties**:

- Stored off-chain in transaction metadata, not on-chain state
- Ordered sequentially within each transaction
- Identified by type and containing transaction
- Queryable via REST API and GraphQL indexer
- Support generic type parameters
- Require `drop` and `store` abilities

## How Events Work

When code emits an event during transaction execution:

1. Event data is serialized and attached to the transaction
2. Validators include events in the committed transaction output
3. Indexers process events and make them queryable
4. Applications query events via REST or GraphQL APIs
5. Events provide an audit trail of contract activity

Unlike state changes that modify resources, events create an append-only log that never changes.

## Practical Examples

**Token Transfer Events:**

```move
struct CoinTransferEvent has drop, store {
    sender: address,
    receiver: address,
    amount: u64,
    coin_type: TypeInfo
}
```

**NFT Marketplace Events:**

```move
struct ListingCreatedEvent has drop, store {
    seller: address,
    token_id: TokenId,
    price: u64,
    expiration: u64
}

struct PurchaseEvent has drop, store {
    buyer: address,
    seller: address,
    token_id: TokenId,
    price: u64
}
```

**DeFi Protocol Events:**

```move
struct SwapEvent has drop, store {
    user: address,
    coin_in_type: TypeInfo,
    coin_out_type: TypeInfo,
    amount_in: u64,
    amount_out: u64,
    fee: u64
}
```

## Use Cases

Events enable powerful off-chain functionality:

1. **User Activity Feeds**: Display transaction history and account activity in wallets and applications.

2. **Real-Time Notifications**: Trigger webhooks or push notifications when specific events occur.

3. **Analytics Dashboards**: Aggregate events to compute metrics like trading volume, user growth, or protocol usage.

4. **Compliance and Auditing**: Maintain immutable audit trails of all contract interactions for regulatory requirements.

5. **State Reconstruction**: Replay events to rebuild application state without querying all resources.

6. **Cross-Contract Coordination**: Monitor events from other contracts to trigger conditional logic.

## Best Practices

**Structured Event Design**: Design events with all information needed by consumers. Include addresses, amounts, timestamps, and type information.

**Consistent Naming**: Use descriptive event names with consistent patterns: `TransferEvent`, `MintEvent`, `BurnEvent`.

**Emit After Success**: Only emit events after operations succeed to avoid confusing off-chain systems with failed attempt notifications.

**Version Events**: When upgrading contracts, consider versioning events or adding optional fields to maintain backward compatibility with indexers.

**Gas Efficiency**: Events are relatively cheap but not free. Emit only essential notifications.

**Type Information**: Include type parameters or TypeInfo when events involve generic types to enable proper deserialization.

## Event Querying

Access events via multiple endpoints:

**REST API by Creation Number**:

```
GET /v1/accounts/{address}/events/{creation_number}
```

**REST API by Handle**:

```
GET /v1/accounts/{address}/events/{event_handle}/{field_name}
```

**GraphQL Indexer** (when available): Provides complex filtering, aggregation, and joins across multiple event types.

## Common Patterns

**Event Handles** (Legacy Pattern):

```move
struct EventStore has key {
    transfer_events: EventHandle<TransferEvent>
}
```

**Modern Event Emission** (Recommended):

```move
// No event handle needed
public entry fun transfer(from: &signer, to: address, amount: u64) {
    // Logic
    event::emit(TransferEvent { from: signer::address_of(from), to, amount });
}
```

The modern approach is simpler and more efficient.

## Related Concepts

- **Event Handles**: Legacy mechanism for organizing events (still supported but not recommended for new code)
- **GraphQL Indexer**: Query engine for complex event analysis
- **REST Event Endpoints**: Direct event access via REST API
- **Transaction Metadata**: Events are stored with transaction results

---

## events_by_creation_number

# events_by_creation_number

## Overview

Retrieve events from a specific event stream identified by an account address and creation number. Each event handle in Aptos has a unique creation number assigned when the handle is created. This endpoint lets you query, paginate, and monitor individual event streams for specific on-chain activities like token transfers, staking rewards, or governance votes.

> **Operational note:** This route also relies on indexer-backed event readers on shared Dwellir Aptos fullnodes. If the backend responds with `internal_error` because the indexer reader is unavailable, use GraphQL or the owning resource as your fallback source of truth.

## Endpoint

`GET /v1/accounts/{address}/events/{creation_number}`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Get the first 10 events from creation number 2 (deposit events for 0x1)
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/events/2?limit=10" \
      -H "Accept: application/json"

    # Paginate from a specific sequence number
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/events/2?start=100&limit=100" \
      -H "Accept: application/json"
```

## Response Fields

- `version` (`string, required`): Ledger version when the event was emitted
- `guid.creation_number` (`string, required`): The creation number identifying this event stream
- `guid.account_address` (`string, required`): The account that owns this event stream
- `sequence_number` (`string, required`): Sequential number within this event stream (starts at 0)
- `type` (`string, required`): Fully qualified Move type of the event payload
- `data` (`object, required`): The structured event payload, fields vary by event type

## Successful Response

```json
[
  {
    "version": "123456789",
    "guid": {
      "creation_number": "2",
      "account_address": "0x1"
    },
    "sequence_number": "42",
    "type": "0x1::coin::DepositEvent",
    "data": {
      "amount": "1000000"
    }
  },
  {
    "version": "123456800",
    "guid": {
      "creation_number": "2",
      "account_address": "0x1"
    },
    "sequence_number": "43",
    "type": "0x1::coin::DepositEvent",
    "data": {
      "amount": "500000"
    }
  }
]
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid address or creation number format

### Error 2

- Code: `resource_not_found`
- Description: Event stream does not exist at this creation number

### Error 3

- Code: `account_not_found`
- Description: Account does not exist

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Get the first 10 events from creation number 2 (deposit events for 0x1)
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/events/2?limit=10" \
  -H "Accept: application/json"

# Paginate from a specific sequence number
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/events/2?start=100&limit=100" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Fetch recent events
events = client.account_events_by_creation_number("0x1", "2", start=None, limit=10)
for event in events:
    print(f"Seq {event['sequence_number']}: {event['type']} at version {event['version']}")
    print(f"  Data: {event['data']}")

# Paginate through all events
def stream_events(client, address, creation_number, start_seq=0):
    seq = start_seq
    while True:
        batch = client.account_events_by_creation_number(
            address, str(creation_number), start=str(seq), limit=100
        )
        if not batch:
            break
        for event in batch:
            yield event
        seq = int(batch[-1]["sequence_number"]) + 1

for event in stream_events(client, "0x1", 2):
    process_event(event)
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Fetch events via raw REST call
const response = await fetch(
  "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/events/2?limit=10",
  { headers: { "Accept": "application/json" } }
);
const events = await response.json();

for (const event of events) {
  console.log(`Event: ${event.type}, Amount: ${event.data.amount}`);
}
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let events = client
    .get_account_events("0x1", "2", Some(0), Some(10))
    .await?;
for event in events.inner() {
    println!("Seq {}: {} at version {}",
        event.sequence_number, event.typ, event.version);
}
```

## Discovering Creation Numbers

Creation numbers are assigned sequentially when event handles are created in an account's resources. To find the creation number for a specific event stream:

1. **Query the resource** that contains the event handle:
   ```bash
   GET /v1/accounts/{address}/resource/0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>
   ```

2. **Find the event handle** in the response:
   ```json
   {
     "data": {
       "deposit_events": {
         "counter": "42",
         "guid": {
           "id": {
             "addr": "0x1",
             "creation_num": "2"
           }
         }
       },
       "withdraw_events": {
         "counter": "15",
         "guid": {
           "id": {
             "addr": "0x1",
             "creation_num": "3"
           }
         }
       }
     }
   }
   ```

3. **Use the creation\_num** value (e.g., `2` for deposits, `3` for withdrawals) with this endpoint.

Common creation numbers for standard accounts:

- `0` - Account creation event
- `1` - Key rotation event
- `2` - CoinStore deposit events (for the first registered coin)
- `3` - CoinStore withdraw events (for the first registered coin)

## Use Cases

1. **Transfer Monitoring**: Track all deposits and withdrawals for an account by monitoring creation numbers 2 and 3 (for CoinStore events), enabling real-time balance tracking and notifications.

2. **Event Stream Processing**: Build event-driven architectures that react to specific on-chain events, such as triggering webhooks when a deposit exceeds a threshold.

3. **Historical Event Analysis**: Paginate through historical events to analyze patterns, aggregate statistics (total volume, transaction counts), or reconstruct state changes over time.

4. **Audit Trail Construction**: Build comprehensive audit logs by retrieving all events emitted by critical accounts (treasury, governance, multisig) in chronological order.

5. **Notification Systems**: Poll for new events at regular intervals and trigger alerts (email, Slack, push notifications) when specific event types or amounts are detected.

6. **DeFi Position Tracking**: Monitor staking events, reward distributions, and liquidity pool events to maintain accurate portfolio tracking.

## Best Practices

**Creation Number Discovery**: Always discover creation numbers dynamically from the containing resource rather than hardcoding them. While standard CoinStore uses 2/3 for deposit/withdraw, custom modules may use different numbers.

**Pagination Strategy**: Use `limit=100` to minimize API calls for bulk historical retrieval. Use the last event's `sequence_number + 1` as the next `start` parameter.

**Sequence Number Properties**: Sequence numbers within a stream are guaranteed to be sequential with no gaps, starting from 0. Missing sequence numbers indicate data synchronization issues.

**Version Ordering**: While sequence numbers order events within a single stream, use the `version` field to establish ordering across different event streams or accounts.

**Legacy vs Modern Events**: This endpoint supports both the legacy event handle system and newer event handles. For new contracts using `0x1::event::emit()`, events may be queried differently through the indexer.

**Rate Limiting**: Avoid polling too frequently. For near-real-time monitoring, poll every 4-5 seconds (matching Aptos block time). For less urgent monitoring, poll every 30-60 seconds.

**Counter Check**: The `counter` field in the event handle resource tells you the total number of events emitted. Use this to determine if there are new events without fetching the events themselves.

## Performance Considerations

Event queries are efficient for reasonable ranges. Fetching 100 events typically completes in 50-100ms. Requesting the maximum of 100 events with complex payloads can take 100-200ms.

Events are stored in chronological order, making forward pagination (increasing sequence numbers) the most efficient access pattern. The creation number index provides O(1) lookup to the event stream root.

For applications requiring comprehensive event analysis across multiple accounts or event types, the GraphQL indexer provides more efficient bulk querying capabilities with complex filtering, aggregation, and cross-account event correlation.

## Related Endpoints

- `/v1/accounts/{address}/events/{event_handle}/{field_name}` - Query events by handle and field name
- `/v1/accounts/{address}/resource/{type}` - Discover event handles and creation numbers
- `/v1/accounts/{address}/resources` - List all resources to find event handles
- `/v1/transactions/by_version/{version}` - Get the transaction that emitted a specific event

---

## events_by_handle

# events_by_handle

## Endpoint

`GET /v1/accounts/{address}/events/{event_handle}/{field_name}`

## Request

### Path Parameters

| Name          | Type   | Required | Description                          |
| ------------- | ------ | -------- | ------------------------------------ |
| address       | string | Yes      | Account address                      |
| event\_handle | string | Yes      | Struct type with events              |
| field\_name   | string | Yes      | Field in the struct producing events |

### Query Parameters

| Name  | Type    | Required | Description       |
| ----- | ------- | -------- | ----------------- |
| start | string  | No       | Starting sequence |
| limit | integer | No       | Page size         |

## Response

### Success Response (200)

Returns an array of event objects from the specified handle:

```json
[
  {
    "version": "123456789",
    "guid": {
      "creation_number": "3",
      "account_address": "0x1"
    },
    "sequence_number": "5",
    "type": "0x1::account::CoinRegisterEvent",
    "data": {
      "type_info": {
        "account_address": "0x1",
        "module_name": "aptos_coin",
        "struct_name": "AptosCoin"
      }
    }
  }
]
```

### Error Responses

| Status | Error Code           | Description                                   |
| ------ | -------------------- | --------------------------------------------- |
| 400    | invalid\_input       | Invalid address, handle, or field name format |
| 404    | resource\_not\_found | Event handle or field doesn't exist           |
| 404    | account\_not\_found  | Account doesn't exist                         |

## Code Examples

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/events/0x1::account::Account/coin_register_events?limit=5" \
  -H "Accept: application/json"
```

Python example:

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
events = client.account_events_by_event_handle(
    "0x1",
    "0x1::account::Account",
    "coin_register_events",
    limit=5
)
```

TypeScript example:

```typescript
const events = await aptos.getEventsByEventHandle({
  accountAddress: "0x1",
  eventHandleStruct: "0x1::account::Account",
  fieldName: "coin_register_events",
  minimumLedgerVersion: 0,
  options: { limit: 5 }
});
```

## Use Cases

This endpoint enables powerful event-driven architecture patterns:

1. **Contract Event Monitoring**: Monitor specific event types emitted by smart contracts, such as tracking all token transfer events or NFT mint events from a marketplace contract.

2. **User Activity Tracking**: Build user activity feeds by querying events from user-controlled resources, showing transaction history and state changes.

3. **Cross-Contract Analytics**: Aggregate events across multiple contracts or accounts to analyze ecosystem-wide trends, such as total trading volume or user adoption metrics.

4. **Real-Time Notifications**: Poll event handles to detect new events and trigger notifications, webhooks, or automated responses for critical contract activities.

5. **State Verification**: Verify that expected state changes occurred by checking for corresponding events, useful for transaction confirmation UIs.

6. **Debugging and Testing**: During development, inspect event emissions to validate contract behavior and ensure events are emitted with correct data.

## Best Practices

**Event Handle Structure**: The event handle path follows the pattern `address::module::Struct/field_name`. The struct must contain an `EventHandle<T>` field with the specified name.

**Type Information**: Always inspect the returned `type` field to understand the event payload structure. Event types are strongly typed in Move and the type string indicates the exact Move struct emitted.

**Pagination**: For event streams with many events, use pagination with the `start` parameter set to the last seen `sequence_number + 1` to avoid missing events or duplicates.

**Polling Frequency**: Poll at reasonable intervals (5-30 seconds) based on your use case. Too frequent polling wastes resources, while too infrequent polling may delay notifications.

**Handle Discovery**: Find available event handles by querying account resources and inspecting struct fields of type `EventHandle<T>`. The ABI from module queries shows event handle field names.

## Performance Considerations

Event queries by handle are optimized with indexed lookups, typically completing in 50-150ms for reasonable limits. Response times increase with larger limit values and complex event payload structures.

This method is more efficient than querying by creation number when you know the specific contract and field name, as it avoids resource enumeration overhead. However, for bulk event analysis across many handles, consider using the GraphQL indexer for better query flexibility and performance.

---

## formal_verification

# formal_verification

Formal verification in Move uses the Move Prover tool to mathematically verify that smart contracts behave correctly under all possible conditions. Unlike traditional testing which checks specific scenarios, formal verification provides mathematical proofs that your code satisfies specified properties for all possible inputs and states.

## Overview

The Move Prover is a sophisticated verification tool that analyzes Move modules and proves that they satisfy formal specifications written in the Move Specification Language (MSL). It uses automated theorem proving techniques to verify safety properties, invariants, and functional correctness of your smart contracts before deployment.

## Technical Implementation

Formal verification works by translating Move code and specifications into logical formulas that can be processed by SMT (Satisfiability Modulo Theories) solvers. The prover checks whether your code can violate any specified invariants or preconditions under any execution path.

### Specification Syntax

```move
module 0x1::verified_coin {
    use std::signer;

    struct Balance has key {
        value: u64
    }

    spec Balance {
        invariant value <= MAX_U64;
    }

    public fun transfer(from: &signer, to: address, amount: u64) acquires Balance {
        let from_addr = signer::address_of(from);
        let from_balance = &mut borrow_global_mut<Balance>(from_addr).value;
        let to_balance = &mut borrow_global_mut<Balance>(to).value;

        *from_balance = *from_balance - amount;
        *to_balance = *to_balance + amount;
    }

    spec transfer {
        requires exists<Balance>(signer::address_of(from));
        requires exists<Balance>(to);
        requires borrow_global<Balance>(signer::address_of(from)).value >= amount;
        ensures borrow_global<Balance>(to).value == old(borrow_global<Balance>(to).value) + amount;
        ensures borrow_global<Balance>(signer::address_of(from)).value ==
                old(borrow_global<Balance>(signer::address_of(from)).value) - amount;
    }
}
```

## Real-World Use Cases

1. **DeFi Protocol Security**: Verify that token supply invariants hold across all transfer, mint, and burn operations, ensuring no tokens can be created or destroyed unexpectedly.

2. **Access Control Validation**: Prove that administrative functions can only be called by authorized accounts and that privilege escalation is impossible.

3. **Asset Conservation**: Verify that total value in lending protocols, DEXes, or vaults remains constant during operations, preventing loss of funds.

4. **Upgrade Safety**: Prove that module upgrades maintain backward compatibility and preserve critical invariants about stored data.

5. **Overflow Protection**: Mathematically verify that arithmetic operations cannot overflow or underflow, eliminating a major class of vulnerabilities.

6. **State Machine Correctness**: Verify that state transitions in governance systems, auctions, or multi-step processes follow valid sequences.

## Best Practices

**Focus on Critical Properties**: Start by verifying the most important safety properties such as asset conservation, access control, and state invariants. Don't try to verify everything at once.

**Use Modular Specifications**: Break down complex specifications into smaller, reusable components using schema and helper functions in MSL.

**Test Specifications**: Specifications can have bugs too. Use the prover's counterexample feature to validate that your specifications catch actual bugs.

**Iterative Refinement**: Begin with simple invariants and progressively add more detailed specifications as you gain confidence in the prover's behavior.

**Performance Optimization**: Use timeouts, specify verification scope, and leverage modular verification to keep proof times manageable for large codebases.

**Documentation**: Specifications serve as precise documentation of your contract's behavior. Keep them readable and well-commented.

## Running the Move Prover

```bash
# Verify all modules in a package
aptos move prove --package-dir .

# Verify specific module
aptos move prove --package-dir . --filter "0x1::verified_coin"

# Generate detailed error traces
aptos move prove --package-dir . --verbose

# Set timeout for proofs
aptos move prove --package-dir . --timeout 120
```

The prover will report any specification violations with counterexamples showing how the property can be violated, or confirm that all specifications hold.

## Related Concepts

- [Testing](https://www.dwellir.com/docs/aptos/testing) - Complement formal verification with comprehensive unit tests
- [Module Structure](https://www.dwellir.com/docs/aptos/module_structure) - Organize code to facilitate verification
- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Understand resource semantics for writing correct specifications

---

## fungible_assets

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# fungible_assets

Fungible Assets (FA) represent the next generation token standard on Aptos, providing enhanced functionality compared to the legacy Coin standard. The GraphQL API enables comprehensive querying of FA balances, metadata, transfer histories, and analytics, essential for wallets, DEXes, portfolio trackers, and any application working with tokens.

## Overview

The Fungible Asset standard improves upon Coins by supporting programmable behaviors, better metadata management, and composability with the Object model. GraphQL queries provide indexed access to all FA data including current balances, historical activities, supply metrics, and token metadata across all fungible assets on Aptos.

## Core Queries

### Account Balances

```graphql
query FaBalances($owner: String!) {
  current_fungible_asset_balances(
    where: { owner_address: { _eq: $owner } }
  ) {
    owner_address
    asset_type
    amount
    last_transaction_version
    metadata {
      name
      symbol
      decimals
      icon_uri
      project_uri
    }
  }
}
```

### Token Metadata

```graphql
query TokenInfo($asset_type: String!) {
  fungible_asset_metadata(
    where: { asset_type: { _eq: $asset_type } }
  ) {
    asset_type
    creator_address
    name
    symbol
    decimals
    icon_uri
    project_uri
    supply_aggregator_table_handle
    supply_aggregator_table_key
  }
}
```

### Transfer History

```graphql
query TransferHistory($owner: String!, $limit: Int!) {
  fungible_asset_activities(
    where: {
      _or: [
        { owner_address: { _eq: $owner } },
        { to_address: { _eq: $owner } }
      ]
    },
    order_by: { transaction_version: desc },
    limit: $limit
  ) {
    transaction_version
    owner_address
    to_address
    amount
    type
    asset_type
    transaction_timestamp
  }
}
```

### Supply Metrics

```graphql
query SupplyMetrics($asset_type: String!) {
  fungible_asset_supply(
    where: { asset_type: { _eq: $asset_type } }
  ) {
    asset_type
    current_supply
    max_supply
    total_minted
    total_burned
  }
}
```

### Top Holders

```graphql
query TopHolders($asset_type: String!, $limit: Int!) {
  current_fungible_asset_balances(
    where: {
      asset_type: { _eq: $asset_type },
      amount: { _gt: "0" }
    },
    order_by: { amount: desc },
    limit: $limit
  ) {
    owner_address
    amount
    last_transaction_version
  }
}
```

## Real-World Use Cases

1. **Wallet Applications**: Display comprehensive token portfolios with balances, prices, and metadata for all FAs held by users across the Aptos ecosystem.

2. **DEX Interfaces**: Query token metadata, verify decimals, fetch logos, and track liquidity for trading pairs on decentralized exchanges.

3. **Portfolio Trackers**: Aggregate holdings across multiple wallets, calculate total values, and track historical balance changes over time.

4. **Token Analytics**: Analyze holder distribution, supply metrics, transfer volumes, and other statistics for tokens and liquidity pools.

5. **Payment Systems**: Verify balances before transactions, fetch current exchange rates, and track payment histories for accounting purposes.

6. **DeFi Dashboards**: Monitor staking positions, lending collateral, farming rewards, and other DeFi activities involving fungible assets.

## Best Practices

**Cache Metadata**: Token metadata (name, symbol, decimals, logo) changes rarely - cache it with long TTLs to reduce API calls.

**Handle Decimals**: Always account for token decimals when displaying amounts - a balance of 1000000 with 6 decimals is actually 1.0 tokens.

**Batch Balance Queries**: Fetch all balances for an address in a single query rather than separate requests per token.

**Track Versions**: Use transaction\_version to detect balance changes and avoid displaying stale data.

**Filter Zero Balances**: Exclude zero-balance entries to avoid cluttering portfolio displays with tokens users no longer hold.

**Use Aggregations**: For analytics, use aggregate queries to compute statistics efficiently rather than fetching all records.

**Pagination**: Implement proper pagination for transfer histories and holder lists to handle large datasets.

## TypeScript Integration

```typescript
import { ApolloClient, gql } from "@apollo/client";

const client = new ApolloClient({
  uri: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql"
});

interface TokenBalance {
  asset_type: string;
  amount: string;
  decimals: number;
  symbol: string;
  name: string;
}

async function getPortfolio(address: string): Promise<TokenBalance[]> {
  const { data } = await client.query({
    query: gql`
      query Portfolio($address: String!) {
        current_fungible_asset_balances(
          where: {
            owner_address: { _eq: $address },
            amount: { _gt: "0" }
          }
        ) {
          asset_type
          amount
          metadata {
            name
            symbol
            decimals
          }
        }
      }
    `,
    variables: { address }
  });

  return data.current_fungible_asset_balances.map((balance: any) => ({
    asset_type: balance.asset_type,
    amount: balance.amount,
    decimals: balance.metadata.decimals,
    symbol: balance.metadata.symbol,
    name: balance.metadata.name
  }));
}

function formatTokenAmount(amount: string, decimals: number): string {
  const value = parseInt(amount) / Math.pow(10, decimals);
  return value.toLocaleString(undefined, {
    minimumFractionDigits: 2,
    maximumFractionDigits: decimals
  });
}
```

## Advanced Queries

### Portfolio Value Tracking

```graphql
query PortfolioWithPrices($owner: String!) {
  balances: current_fungible_asset_balances(
    where: {
      owner_address: { _eq: $owner },
      amount: { _gt: "0" }
    }
  ) {
    asset_type
    amount
    metadata {
      name
      symbol
      decimals
      icon_uri
    }
  }
}
```

### Token Distribution Analysis

```graphql
query HolderDistribution($asset_type: String!) {
  total_holders: current_fungible_asset_balances_aggregate(
    where: {
      asset_type: { _eq: $asset_type },
      amount: { _gt: "0" }
    }
  ) {
    aggregate { count }
  }

  large_holders: current_fungible_asset_balances_aggregate(
    where: {
      asset_type: { _eq: $asset_type },
      amount: { _gt: "1000000000" }
    }
  ) {
    aggregate { count }
  }

  total_supply: fungible_asset_supply(
    where: { asset_type: { _eq: $asset_type } }
  ) {
    current_supply
  }
}
```

### Activity Feed

```graphql
query RecentActivities($owner: String!, $limit: Int!) {
  fungible_asset_activities(
    where: {
      _or: [
        { owner_address: { _eq: $owner } },
        { to_address: { _eq: $owner } }
      ]
    },
    order_by: { transaction_version: desc },
    limit: $limit
  ) {
    transaction_version
    owner_address
    to_address
    amount
    type
    asset_type
    transaction_timestamp
    metadata {
      symbol
      decimals
    }
  }
}
```

## Fungible Assets vs Coins

The Fungible Asset standard offers several improvements over the legacy Coin standard:

- **Object Integration**: FAs integrate with the Object model for better composability
- **Metadata Standards**: Built-in metadata support with URLs for icons and project info
- **Programmable Transfers**: Support for custom transfer logic and restrictions
- **Better Events**: More comprehensive event emissions for indexing
- **Future-Proof**: Designed for long-term extensibility

## Related Concepts

- [GraphQL Overview](https://www.dwellir.com/docs/aptos/graphql/overview) - GraphQL indexer introduction
- [Token Activities](https://www.dwellir.com/docs/aptos/token_activities) - NFT and token transfers
- [Aggregations](https://www.dwellir.com/docs/aptos/aggregations) - Statistical queries
- [Object Model](https://www.dwellir.com/docs/aptos/object_model) - Object-based asset design

---

## GraphQL API Overview

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# GraphQL API Overview

The Aptos GraphQL indexer gives you indexed, filterable access to transaction history, token activity, account state, and aggregate analytics without having to stitch together multiple REST requests yourself. Once GraphQL access is enabled for your API key, use `https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql` for mainnet queries.

## When to Use GraphQL

GraphQL is the better fit when you need:

- multi-table reads such as balances plus token metadata in one request
- server-side filtering, ordering, and pagination for dashboards or explorers
- aggregate queries for counts, sums, and activity rollups
- a predictable response shape driven by the exact fields your UI needs

For canonical ledger reads, transaction submission, or account-specific REST workflows, use the Aptos REST endpoints. For indexed history and analytics, GraphQL is usually the faster path.

## Request Shape

Every request is a standard GraphQL POST with a `query` string and optional `variables` object:

```json
{
  "query": "query LedgerInfo($limit: Int!) { ledger_infos(limit: $limit, order_by: { version: desc }) { chain_id version timestamp } }",
  "variables": {
    "limit": 1
  }
}
```

That lets you keep queries reusable and move environment-specific inputs, such as account addresses or time windows, into variables instead of string interpolation.

## Starter Query

```graphql
query LedgerInfo($limit: Int!) {
  ledger_infos(limit: $limit, order_by: { version: desc }) {
    chain_id
    version
    timestamp
  }
}
```

```bash
curl -X POST https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query LedgerInfo($limit: Int!) { ledger_infos(limit: $limit, order_by: { version: desc }) { chain_id version timestamp } }",
    "variables": { "limit": 1 }
  }'
```

This is a good health check because it exercises filtering, ordering, and the latest indexed ledger state in one small response.

## Common Query Patterns

Most production GraphQL usage falls into a few repeatable patterns:

- **lookup by address or asset type** with `where` filters
- **latest-first activity feeds** with `order_by` and `limit`
- **portfolio views** that fetch balances together with related metadata
- **analytics panels** that use `_aggregate` tables for counts and rollups

Start with a narrow filter and a low `limit`, then expand once you know the table and relation shape you need.

## Operational Notes

- GraphQL access is enabled per account. If the endpoint is not provisioned for your key yet, request enablement before building against it.
- Prefer variables over string-built queries so clients stay type-safe and easier to cache.
- Ask only for the fields you render. Smaller selection sets reduce payload size and make caching more effective.
- Add `order_by` explicitly for paged queries so your client does not rely on implicit ordering.
- Use aggregate tables for metrics and dashboards rather than fetching large result sets just to count them client-side.

## Related Guides

- [User Transactions](https://www.dwellir.com/docs/aptos/user_transactions) for indexed transaction history
- [Fungible Assets](https://www.dwellir.com/docs/aptos/fungible_assets) for balances and token metadata
- [Aggregations](https://www.dwellir.com/docs/aptos/aggregations) for counts and rollups
- [Subscriptions](https://www.dwellir.com/docs/aptos/subscriptions) for real-time GraphQL updates

---

## healthy

# healthy

## Overview

Check the health and availability of the Aptos REST API node. This endpoint returns HTTP 200 when the node is operational and synced, making it ideal for monitoring, load balancing, and automated health checks in production environments.

## Endpoint

`GET /v1/-/healthy`

## Request

### Path Parameters

None.

### Query Parameters

None.

### Request Body

None.

## Response

### Success Response (200)

Returns HTTP 200 with an empty or minimal response body when the node is healthy and ready to serve requests. The node is considered healthy when:

- The REST API service is running and responsive
- The underlying node is syncing or fully synced with the network
- Database connections are operational
- Critical system resources are available

### Error Responses

| Status | Error Code           | Description                                   |
| ------ | -------------------- | --------------------------------------------- |
| 503    | service\_unavailable | Node is unhealthy, not synced, or starting up |
| 500    | internal\_error      | Critical error preventing normal operation    |

Any non-200 response indicates the node should not receive production traffic.

## Code Examples

Shell script for monitoring:

```bash
curl -s -X GET -o /dev/null -w "%{http_code}\n" https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy -H "Accept: application/json"
```

Python monitoring script:

```python
import requests

def is_node_healthy(api_key):
    try:
        response = requests.get(
            f"https://api-aptos-mainnet.n.dwellir.com/{api_key}/v1/-/healthy",
            timeout=5
        )
        return response.status_code == 200
    except requests.exceptions.RequestException:
        return False

if is_node_healthy("YOUR_API_KEY"):
    print("Node is healthy")
else:
    print("Node is unhealthy")
```

TypeScript health check:

```typescript
async function checkNodeHealth(apiKey: string): Promise<boolean> {
  try {
    const response = await fetch(
      `https://api-aptos-mainnet.n.dwellir.com/${apiKey}/v1/-/healthy`,
      { signal: AbortSignal.timeout(5000) }
    );
    return response.status === 200;
  } catch (error) {
    return false;
  }
}
```

Docker healthcheck in docker-compose.yml:

```yaml
services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
```

## Use Cases

This endpoint is essential for production infrastructure:

1. **Load Balancer Health Checks**: Configure load balancers (AWS ALB, nginx, HAProxy) to use this endpoint for backend health checks, automatically routing traffic away from unhealthy nodes.

2. **Kubernetes Readiness Probes**: Set up Kubernetes readiness and liveness probes to ensure pods are only marked ready when the Aptos node is fully synced and operational.

3. **Monitoring and Alerting**: Integrate with monitoring systems (Prometheus, Datadog, New Relic) to track node availability and trigger alerts when health checks fail.

4. **Automated Failover**: Build high-availability systems that automatically switch to backup API endpoints when the primary node becomes unhealthy.

5. **CI/CD Pipeline Gates**: Use health checks in deployment pipelines to verify services are operational before promoting to production or completing rolling updates.

6. **Service Discovery**: Register nodes with service discovery systems (Consul, etcd) and use health checks to maintain an accurate registry of available endpoints.

## Best Practices

**Timeout Configuration**: Set reasonable timeouts (3-5 seconds) for health check requests. If a node doesn't respond quickly, it's likely unhealthy and shouldn't serve traffic.

**Check Frequency**: Balance between responsiveness and load. For critical services, check every 10-30 seconds. For monitoring dashboards, 60 seconds is typically sufficient.

**Retry Logic**: Implement exponential backoff for retries. Don't immediately mark a node as unhealthy on a single failed check - wait for 2-3 consecutive failures.

**Circuit Breaker Pattern**: After detecting an unhealthy node, implement a circuit breaker that waits before rechecking. Avoid overwhelming an unhealthy node with continuous health checks.

**Multiple Nodes**: Never rely on a single node. Always maintain connections to multiple API endpoints and use health checks to select healthy ones dynamically.

**Logging**: Log health check failures with timestamps and status codes for troubleshooting and capacity planning.

## Performance Considerations

Health check requests are extremely lightweight and typically complete in under 20ms. They don't touch the blockchain state layer - the node simply reports its operational status.

However, health checks do consume API rate limits and network resources. Avoid checking more frequently than every 5-10 seconds to prevent unnecessary load on shared infrastructure.

For Dwellir's managed API infrastructure, health checks are already performed internally at the load balancer level. The health endpoint is exposed primarily for client-side monitoring and verification purposes.

## Integration with Other Endpoints

Combine health checks with the `/v1` (ledger\_info) endpoint for more detailed node status:

- `/v1/-/healthy` - Quick operational check (< 20ms)
- `/v1` - Detailed sync status with version information (50-100ms)

Use `/healthy` for rapid health verification, then query `/v1` for diagnostic information if health checks start failing.

---

## Aptos Historical Transaction Replay

The Aptos Transaction Stream is not generally available. Email
<support@dwellir.com> to join the early-access list.

# Aptos Historical Transaction Replay

Replay is the same RPC as a live tail, with `starting_version` set. Use it to
backfill a new processor, recover after an outage, or rebuild a table from a
schema change.

There is no separate replay service or endpoint — see the
[Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) for the service
definition.

How far back you can replay depends on the retention of the nodes serving your
account, and deep historical range is provisioned rather than assumed. Confirm the
available range with <support@dwellir.com> before
designing a backfill that depends on it. Do not assume replay from genesis is
available.

## Replay From a Version

```typescript
const request = {
  starting_version: '100000000',
};

const stream = client.GetTransactions(request, metadata);

stream.on('data', (response) => {
  for (const tx of response.transactions) {
    processTransaction(tx);
  }
  checkpoint.observe(response);
});
```

A replay stream does not end when it reaches the head of chain. It transitions
into a live tail on the same connection, which is what makes catch-up-then-tail a
single code path rather than two.

## Bound the Range

To replay a fixed window rather than continuing into the tail, set
`transactions_count`:

```typescript
// Replay exactly 5,000,000 transactions, then the stream completes.
const request = {
  starting_version: '100000000',
  transactions_count: '5000000',
};
```

`transactions_count` counts transactions, not versions or messages. Use it when
you want the stream to terminate on its own; cancel client-side when your stopping
condition depends on decoded content.

## Tune the Batch Size

Backfills are the one case where `batch_size` matters. The tail sends roughly one
message per block regardless, but a replay can fill batches, and larger batches
mean fewer metered messages for the same number of transactions.

```typescript
const request = {
  starting_version: resumeFrom.toString(),
  batch_size: 1000, // Default and maximum. Values above 1000 are rejected.
};
```

Since the billed unit is the message, leaving `batch_size` at its default of 1000
is also the cheapest setting for a bulk backfill. Reduce it only if large batches
cause memory pressure in your consumer.

## Resume Without Gaps

Replay jobs are long enough that they will be interrupted. Store progress from
`processed_range.last_version` and restart from the version after it:

```typescript
class ReplayJob {
  async run(fallbackStart: bigint, endVersion: bigint) {
    const stored = await this.loadCheckpoint();
    const start = stored === null ? fallbackStart : stored + 1n;

    if (start > endVersion) return;

    const stream = client.GetTransactions(
      { starting_version: start.toString() },
      metadata
    );

    stream.on('data', async (response) => {
      const last = BigInt(response.processed_range.last_version);

      for (const tx of response.transactions) {
        if (BigInt(tx.version) > endVersion) {
          stream.cancel();
          return this.finish();
        }
        await this.process(tx);
      }

      await this.saveCheckpoint(last > endVersion ? endVersion : last);
    });
  }
}
```

Commit the decoded rows and the checkpoint in one database transaction. A
checkpoint written ahead of its data turns any crash into a silent gap that only
surfaces much later as missing history.

## Splitting Work Across Workers

Ledger versions are contiguous and ordered, so a range splits cleanly across
workers — each opens its own bounded stream over a disjoint slice:

```typescript
async function parallelReplay(start: bigint, end: bigint, workers: number) {
  const span = (end - start) / BigInt(workers);

  await Promise.all(
    Array.from({ length: workers }, (_, i) => {
      const from = start + span * BigInt(i);
      const to = i === workers - 1 ? end : from + span - 1n;
      return new ReplayJob(`replay_${i}`).run(from, to);
    })
  );
}
```

Two caveats before reaching for this:

- **Every worker is a separate metered stream.** Splitting a backfill across eight
  workers does not change the transaction count, but it does add per-message
  overhead and eight concurrent consumers against one rate limit.
- **The rate limit is per account, not per key**, so parallel workers compete with
  each other *and* with your production traffic. See
  [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#scope-per-account-not-per-key).

Give each worker its own checkpoint row, and treat the backfill as complete only
when every slice has committed.

## Throughput Tips

- **Bulk insert per batch**, not per transaction.
- **Drop non-essential indexes** during a large backfill and rebuild after.
- **Decode only what you store.** Full transaction payloads are large, and parsing
  fields you discard is usually the bottleneck before the network is.
- **Apply a server-side filter** if the backfill targets specific accounts or
  functions. It cuts bytes, parsing, and metered messages together.
- **Run backfills off-peak** when they share an account with production traffic.

## Related Guides

- [Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) — service definition and metering
- [Real-Time Streaming](https://www.dwellir.com/docs/aptos/real_time) — tailing after catch-up
- [Custom Processors](https://www.dwellir.com/docs/aptos/custom_processors) — decoding and write patterns
- [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits) — plan limits and per-account scope

---

## key_rotation

# key_rotation

Key rotation on Aptos allows users to change their account's authentication key while preserving the account address, enabling recovery from compromised keys, upgrading security schemes, and transitioning to different authentication methods without losing assets or on-chain identity.

## Overview

Unlike traditional blockchains where accounts are permanently tied to a single private key, Aptos separates account addresses from authentication keys. This architecture enables users to rotate their keys for security purposes while maintaining the same address. Key rotation supports both proven rotations (where you have the old key) and unproven rotations (using social recovery or multi-sig authorization).

## How Key Rotation Works

Every Aptos account has two components: the permanent address derived from the initial public key, and a mutable authentication key that controls access. When you rotate keys, only the authentication key changes while the address remains constant.

```move
// Using Aptos CLI for key rotation
aptos account rotate-key \
  --new-private-key-file ~/.aptos/new_key.key \
  --profile mainnet

// Programmatic key rotation
module 0x1::key_manager {
    use std::signer;
    use aptos_framework::account;

    public entry fun rotate_authentication_key(
        account: &signer,
        new_auth_key: vector<u8>
    ) {
        account::rotate_authentication_key(account, new_auth_key);
    }
}
```

## Proven Rotation

Proven rotation requires the current private key to authorize the key change:

```typescript
import { Aptos, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const aptos = new Aptos();

// Current account (old key)
const oldPrivateKey = new Ed25519PrivateKey("0x...");
const account = Account.fromPrivateKey({ privateKey: oldPrivateKey });

// Generate new key
const newPrivateKey = Ed25519PrivateKey.generate();
const newAuthKey = newPrivateKey.publicKey().authKey();

// Rotate to new key
const transaction = await aptos.rotateAuthKey({
  sender: account,
  newAuthKey: newAuthKey
});

console.log(`Key rotated: ${transaction.hash}`);
```

## Unproven Rotation

Unproven rotation allows key changes through alternative authorization mechanisms like multi-sig or social recovery when the original key is lost:

```move
module 0x1::recovery {
    use std::signer;
    use aptos_framework::account;

    struct RecoveryConfig has key {
        guardians: vector<address>,
        threshold: u64
    }

    public entry fun setup_recovery(
        account: &signer,
        guardians: vector<address>,
        threshold: u64
    ) {
        move_to(account, RecoveryConfig { guardians, threshold });
    }

    public entry fun recover_account(
        recovered_addr: address,
        new_auth_key: vector<u8>,
        guardian_signatures: vector<vector<u8>>
    ) acquires RecoveryConfig {
        let config = borrow_global<RecoveryConfig>(recovered_addr);
        // Verify threshold of guardian signatures
        // Then rotate to new key
        // account::rotate_authentication_key_call(recovered_addr, new_auth_key);
    }
}
```

## Real-World Use Cases

1. **Security Incidents**: Immediately rotate keys when you suspect a private key has been compromised, protecting assets before an attacker can act.

2. **Hardware Wallet Migration**: Transition from a software wallet to a hardware wallet for enhanced security without changing your on-chain address.

3. **Social Recovery**: Implement social recovery systems where trusted friends or family can help recover accounts if keys are lost.

4. **Corporate Key Management**: Rotate employee access keys when staff changes while maintaining consistent corporate account addresses.

5. **Multi-Sig Evolution**: Upgrade from single-key control to multi-sig authorization as account value or importance grows.

6. **Custody Transitions**: Transfer custody of accounts between different custodians or security providers without asset transfers.

## Best Practices

**Verify New Keys**: Always verify you can sign with new keys before finalizing rotation. Test on testnet first for critical accounts.

**Secure Key Generation**: Generate new keys using cryptographically secure random number generators in isolated environments.

**Backup Immediately**: Back up new private keys in multiple secure locations before completing rotation.

**Document Rotation**: Maintain records of key rotations including dates, reasons, and new key fingerprints for audit purposes.

**Test Recovery Procedures**: Regularly test your recovery mechanisms to ensure they work before an emergency.

**Use Time Locks**: Consider implementing time-delayed rotations for high-value accounts to allow cancellation if unauthorized.

**Monitor After Rotation**: Watch account activity closely after rotation to detect any unauthorized access attempts.

## Key Rotation with Multi-Sig

Combine key rotation with multi-sig for enhanced security:

```move
module 0x1::multisig_rotation {
    use aptos_framework::account;
    use aptos_framework::multisig_account;

    public entry fun propose_key_rotation(
        proposer: &signer,
        multisig_address: address,
        new_auth_key: vector<u8>
    ) {
        // Create proposal to rotate multisig account key
        // Requires threshold approval from signers
    }

    public entry fun approve_key_rotation(
        approver: &signer,
        multisig_address: address,
        proposal_id: u64
    ) {
        // Approve the key rotation proposal
    }
}
```

## Security Considerations

**Old Key Compromise**: After rotation, the old private key can no longer control the account, but it could still be used to attempt social engineering attacks.

**Rotation Timing**: Complete rotations quickly once initiated to minimize the window where multiple keys could theoretically control the account.

**Authentication vs Address**: Remember that rotating the authentication key doesn't change the account address, so on-chain references remain valid.

**Transaction Replay**: Signed but unsubmitted transactions from before rotation will fail after the key changes.

**Emergency Contacts**: Maintain emergency contact information with trusted parties who can assist with recovery if needed.

## CLI Commands

```bash
# Generate new key pair
aptos key generate --output-file ~/.aptos/new_key.key

# Rotate to new key
aptos account rotate-key \
  --new-private-key-file ~/.aptos/new_key.key \
  --profile mainnet

# Verify rotation
aptos account lookup-address \
  --profile mainnet

# Test signing with new key
aptos move run \
  --function-id 0x1::aptos_account::test_transaction \
  --profile mainnet
```

## Related Concepts

- [Multi-Agent Transactions](https://www.dwellir.com/docs/aptos/multi_agent) - Coordinate multiple signers
- [Resource Accounts](https://www.dwellir.com/docs/aptos/resource_accounts) - Accounts without private keys
- [Authentication](https://www.dwellir.com/docs/aptos/authentication) - Authentication methods
- [Sponsored Transactions](https://www.dwellir.com/docs/aptos/sponsored_transactions) - Gasless key rotation

---

## ledger_info

# ledger_info

## Overview

Retrieve current ledger information and chain metadata. This is the most fundamental Aptos REST API endpoint, returning the chain ID, current epoch, latest ledger version, block height, and node role. It serves as the starting point for transaction building, sync verification, and network health monitoring.

## Endpoint

`GET /v1`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1" \
      -H "Accept: application/json"
```

## Response Fields

- `chain_id` (`integer, required`): Network identifier: `1` = mainnet, `2` = testnet, other values for devnets
- `epoch` (`string, required`): Current epoch number; increments when the validator set changes
- `ledger_version` (`string, required`): Latest committed transaction version (global sequence number)
- `oldest_ledger_version` (`string, required`): Oldest version available on this node (pruned nodes start higher than 0)
- `ledger_timestamp` (`string, required`): Timestamp of the latest committed transaction in microseconds since Unix epoch
- `block_height` (`string, required`): Latest block height (number of blocks since genesis)
- `oldest_block_height` (`string, required`): Oldest block available on this node
- `node_role` (`string, required`): Node type: `full_node` or `validator`
- `git_hash` (`string, required`): Git commit hash of the node software

## Successful Response

```json
{
  "chain_id": 1,
  "epoch": "5000",
  "ledger_version": "500000000",
  "oldest_ledger_version": "0",
  "ledger_timestamp": "1700000000000000",
  "block_height": "150000000",
  "oldest_block_height": "0",
  "node_role": "full_node",
  "git_hash": "abc123..."
}
```

## Error Responses

### Error 1

- Description: Network identifier: `1` = mainnet, `2` = testnet, other values for devnets

### Error 2

- Description: Current epoch number; increments when the validator set changes

### Error 3

- Description: Latest committed transaction version (global sequence number)

### Error 4

- Description: Oldest version available on this node (pruned nodes start higher than 0)

### Error 5

- Description: Timestamp of the latest committed transaction in microseconds since Unix epoch

### Error 6

- Description: Latest block height (number of blocks since genesis)

### Error 7

- Description: Oldest block available on this node

### Error 8

- Description: Node type: `full_node` or `validator`

### Error 9

- Description: Git commit hash of the node software

## Code Examples

cURL
Python
TypeScript
Rust

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
info = client.info()

print(f"Chain ID:       {info['chain_id']}")
print(f"Epoch:          {info['epoch']}")
print(f"Ledger version: {info['ledger_version']}")
print(f"Block height:   {info['block_height']}")

# Convert timestamp to human-readable
import datetime
ts_seconds = int(info['ledger_timestamp']) / 1_000_000
dt = datetime.datetime.fromtimestamp(ts_seconds, tz=datetime.timezone.utc)
print(f"Latest block:   {dt.isoformat()}")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

const ledgerInfo = await aptos.getLedgerInfo();
console.log(`Chain ID:    ${ledgerInfo.chain_id}`);
console.log(`Epoch:       ${ledgerInfo.epoch}`);
console.log(`Version:     ${ledgerInfo.ledger_version}`);
console.log(`Block height: ${ledgerInfo.block_height}`);

// Check sync freshness
const ageMs = Date.now() - Number(ledgerInfo.ledger_timestamp) / 1000;
console.log(`Data age: ${(ageMs / 1000).toFixed(1)}s`);
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let info = client.get_ledger_information().await?;

println!("Chain ID: {}", info.inner().chain_id);
println!("Epoch: {}", info.inner().epoch);
println!("Version: {}", info.inner().version);
println!("Block height: {}", info.inner().block_height);
```

## Use Cases

1. **Transaction Building**: Retrieve the current chain ID and ledger version, both required for constructing valid transactions. The chain ID prevents replay attacks across different networks (mainnet vs testnet).

2. **Sync Status Verification**: Monitor the node's sync progress by comparing `ledger_version` and `ledger_timestamp` against known network state. A `ledger_timestamp` more than 30 seconds behind real time indicates the node is not fully synced.

3. **Historical Query Planning**: Use `oldest_ledger_version` and `oldest_block_height` to determine the range of available historical data. Queries before these values will fail with 404 errors.

4. **Block Explorer Navigation**: Power block explorers with the current height and version, enabling users to navigate to the latest blocks and understand overall chain progress.

5. **Time-Based Queries**: Convert between wall-clock time and ledger versions using `ledger_timestamp`. This enables retrieving state "as of" a specific point in time by finding the corresponding version.

6. **Network Health Monitoring**: Track `epoch` changes to monitor validator set transitions. Track `ledger_timestamp` progression to detect chain stalls or slowdowns. Alert when the gap between real time and ledger time exceeds a threshold.

7. **Multi-Node Comparison**: Query multiple API endpoints and compare `ledger_version` values to verify they are in sync. A large version gap between providers may indicate network partitions or node issues.

## Response Fields Deep Dive

### chain\_id

The chain ID is a critical safety parameter:

- **Mainnet**: `1`
- **Testnet**: `2`
- **Devnet**: varies by deployment

Always validate `chain_id` matches your expected network before submitting transactions. Submitting a mainnet transaction to testnet (or vice versa) will fail due to chain ID mismatch in the signature.

### epoch

Epochs define validator set boundaries. When the epoch increments:

- The validator set may change (new validators join, existing ones leave)
- Staking rewards are distributed
- Governance proposals may take effect

Epoch duration on mainnet is approximately 2 hours. Track epoch transitions to monitor governance and staking events.

### ledger\_version vs block\_height

These are related but distinct concepts:

- `ledger_version` counts individual transactions (global sequence number)
- `block_height` counts blocks (each containing one or more transactions)
- A single block contains `last_version - first_version + 1` transactions

Use `ledger_version` for transaction-level operations and `block_height` for block-level operations.

### ledger\_timestamp

The timestamp is in **microseconds** since Unix epoch (not milliseconds or seconds). Common conversions:

- To seconds: divide by 1,000,000
- To milliseconds: divide by 1,000
- To JavaScript Date: `new Date(Number(timestamp) / 1000)`

## Best Practices

**Caching Strategy**: Ledger info changes every block (approximately every 4 seconds on mainnet). Cache this data for 2-5 seconds to minimize API calls while maintaining reasonable freshness.

**Chain ID Validation**: Always verify `chain_id` matches your expected network before building transactions. This single check prevents accidental cross-network submissions.

**Version Management**: When building transactions, fetch fresh ledger info to get the latest version. Stale version data can cause transaction expiration issues or references to pruned state.

**Historical Data Awareness**: Check `oldest_ledger_version` before attempting historical queries. Nodes prune old data, and querying beyond the oldest version returns errors.

**Timestamp Precision**: The `ledger_timestamp` is in microseconds since Unix epoch. Ensure your timestamp conversion handles this correctly -- a common bug is treating it as milliseconds.

**Health Check Integration**: Incorporate this endpoint into your application's health checks. If `ledger_timestamp` is more than 30 seconds behind, treat the API as degraded and consider failing over to an alternative endpoint.

## Performance Considerations

This endpoint is highly optimized and typically responds in 10-30ms. It queries metadata from the node's fast-access cache layer without touching the transaction database or blockchain state.

Response size is minimal (under 1KB), making it suitable for frequent polling. For applications requiring real-time updates, poll every 4-5 seconds (matching block time) rather than faster, which provides no additional freshness.

The `node_role` field indicates whether you are querying a validator or fullnode. Dwellir's API endpoints are fullnodes, which provide stable, scalable access with minimal lag behind validators (typically 1-2 seconds).

## Related Endpoints

- `/v1/-/healthy` - Quick health check endpoint (returns 200 if node is healthy)
- `/v1/blocks/by_height/{height}` - Fetch a specific block by height
- `/v1/transactions` - List recent transactions starting from the latest version
- `/v1/spec` - OpenAPI specification for all available endpoints

---

## module_structure

# module_structure

Move modules are the fundamental building blocks of smart contracts on Aptos. They encapsulate types, functions, and constants into reusable, composable units that can be published on-chain and invoked by transactions. Understanding proper module structure is essential for building maintainable, secure, and efficient smart contracts.

## Overview

Move modules define types (structs), functions (both public and private), and constants under a specific account address. On Aptos, modules are published to the blockchain under an account address and become immutable once deployed, though they can be upgraded following specific compatibility rules. Each module has a unique identifier consisting of the publishing account address and the module name (e.g., `0x1::coin`).

## Module Anatomy

A well-structured Move module typically contains the following components organized in a logical order:

```move
module 0x1::example_token {
    // 1. Imports
    use std::signer;
    use std::string::String;
    use aptos_framework::event;
    use aptos_framework::timestamp;

    // 2. Error codes
    const ENOT_AUTHORIZED: u64 = 1;
    const EINSUFFICIENT_BALANCE: u64 = 2;
    const EALREADY_INITIALIZED: u64 = 3;

    // 3. Constants
    const MAX_SUPPLY: u64 = 1_000_000_000;
    const DECIMALS: u8 = 8;

    // 4. Structs (types)
    struct TokenStore has key {
        balance: u64,
        frozen: bool
    }

    struct Capabilities has key {
        mint_cap: MintCapability,
        burn_cap: BurnCapability
    }

    struct MintCapability has store, drop {}
    struct BurnCapability has store, drop {}

    // 5. Events
    struct TransferEvent has drop, store {
        from: address,
        to: address,
        amount: u64,
        timestamp: u64
    }

    // 6. Event handles
    struct EventStore has key {
        transfer_events: event::EventHandle<TransferEvent>
    }

    // 7. Public entry functions (transaction entry points)
    public entry fun initialize(account: &signer) {
        // Implementation
    }

    public entry fun transfer(from: &signer, to: address, amount: u64) acquires TokenStore, EventStore {
        // Implementation
    }

    // 8. Public functions (callable by other modules)
    public fun balance_of(addr: address): u64 acquires TokenStore {
        // Implementation
        0
    }

    // 9. Public(friend) functions
    public(friend) fun mint(cap: &MintCapability, to: address, amount: u64) acquires TokenStore {
        // Implementation
    }

    // 10. Internal functions
    fun internal_transfer(from: address, to: address, amount: u64) acquires TokenStore {
        // Implementation
    }

    // 11. Helper functions
    fun validate_amount(amount: u64): bool {
        amount > 0 && amount <= MAX_SUPPLY
    }
}
```

## Abilities and Type Safety

Move's ability system provides fine-grained control over how types can be used. The four abilities are:

- **key**: Can be stored as a top-level resource under an account (required for global storage)
- **store**: Can be stored inside other structs with the `key` ability
- **copy**: Values can be copied (duplicated)
- **drop**: Values can be implicitly discarded

Use abilities judiciously to enforce proper resource semantics and prevent common vulnerabilities like resource duplication or accidental deletion.

## Real-World Use Cases

1. **Token Contracts**: Structure modules to manage fungible or non-fungible token supply, balances, and metadata with proper access controls and event emissions.

2. **DeFi Protocols**: Organize complex financial logic into separate modules for lending, borrowing, liquidity pools, and governance, each with clear interfaces.

3. **NFT Marketplaces**: Create modular systems with separate modules for listings, bids, royalties, and transfers to facilitate maintainability and upgrades.

4. **Governance Systems**: Structure voting, proposal, and execution logic into distinct modules with clear separation of concerns.

5. **Access Control Systems**: Build reusable authentication and authorization modules that other contracts can leverage through public interfaces.

6. **Oracle Integration**: Create structured modules that fetch and validate external data with proper error handling and event emission.

## Best Practices

**Minimize Entry Function Logic**: Keep entry functions thin by delegating complex logic to internal functions. This improves testability and code reuse.

**Emit Comprehensive Events**: Emit events for all state changes to enable off-chain indexing and user notifications. Include relevant context in event data.

**Error Code Organization**: Define all error codes as module constants at the top of the file with descriptive names prefixed with 'E'.

**Function Ordering**: Follow a consistent ordering pattern (entry functions first, then public, then internal) to improve code readability.

**Use Friend Declarations**: Leverage the `friend` visibility modifier to expose functions only to trusted modules while maintaining encapsulation.

**Document Acquires**: Always document which resources a function acquires to help developers understand global storage access patterns.

**Separate Concerns**: Split large modules into smaller, focused modules that each handle a specific concern or feature.

## Module Dependencies

```move
// In Move.toml
[dependencies]
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework", rev = "mainnet" }

[addresses]
my_project = "_"
```

Properly manage dependencies in your Move.toml file and use named addresses to make modules portable across different deployment environments.

## Related Concepts

- [Upgradability](https://www.dwellir.com/docs/aptos/upgradability) - Learn how to safely upgrade modules
- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Understand Move's resource model
- [Testing](https://www.dwellir.com/docs/aptos/testing) - Best practices for testing module functionality
- [View Functions](https://www.dwellir.com/docs/aptos/view_functions) - Implement gas-free read operations

---

## multi_agent

# multi_agent

Multi-agent transactions enable multiple independent signers to authorize a single transaction on Aptos, allowing complex operations that require coordination between different accounts. This feature is essential for marketplaces, atomic swaps, escrow services, and any scenario where multiple parties must agree to a state change.

## Overview

Traditional blockchain transactions have a single sender who pays gas and authorizes all operations. Multi-agent transactions extend this model by allowing additional signers (secondary signers) to authorize operations on their own resources within the same atomic transaction. All signers must provide signatures before the transaction can execute, ensuring all parties consent to the operation.

## Technical Implementation

Multi-agent transactions use a special transaction payload that includes addresses of all required signers. Each signer must sign the same transaction hash, and the transaction only executes if all signatures are valid.

```move
module 0x1::marketplace {
    use std::signer;
    use aptos_framework::coin;
    use aptos_framework::aptos_coin::AptosCoin;

    struct Listing has key {
        price: u64,
        owner: address
    }

    struct NFT has key, store {
        id: u64,
        metadata: vector<u8>
    }

    // Requires both buyer and seller signatures
    public entry fun purchase_nft(
        buyer: &signer,
        seller: &signer,
        nft_id: u64
    ) acquires NFT, Listing {
        let seller_addr = signer::address_of(seller);
        let buyer_addr = signer::address_of(buyer);

        // Get listing from seller
        let listing = borrow_global<Listing>(seller_addr);
        let price = listing.price;

        // Transfer payment from buyer to seller
        coin::transfer<AptosCoin>(buyer, seller_addr, price);

        // Transfer NFT from seller to buyer
        let nft = move_from<NFT>(seller_addr);
        move_to(buyer, nft);

        // Clean up listing
        let Listing { price: _, owner: _ } = move_from<Listing>(seller_addr);
    }
}
```

## Creating Multi-Agent Transactions

### TypeScript SDK

```typescript
import { Aptos, Account, AccountAuthenticator } from "@aptos-labs/ts-sdk";

const aptos = new Aptos();

// Create accounts
const buyer = Account.generate();
const seller = Account.generate();

// Build multi-agent transaction
const transaction = await aptos.transaction.build.multiAgent({
  sender: buyer.accountAddress,
  secondarySignerAddresses: [seller.accountAddress],
  data: {
    function: "0x1::marketplace::purchase_nft",
    functionArguments: [seller.accountAddress, 123]
  }
});

// Both parties sign
const buyerAuth = aptos.transaction.sign({ signer: buyer, transaction });
const sellerAuth = aptos.transaction.sign({ signer: seller, transaction });

// Submit with all signatures
const committedTxn = await aptos.transaction.submit.multiAgent({
  transaction,
  senderAuthenticator: buyerAuth,
  additionalSignersAuthenticators: [sellerAuth]
});

await aptos.waitForTransaction({ transactionHash: committedTxn.hash });
```

### Python SDK

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import EntryFunction, TransactionPayload

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

buyer = Account.generate()
seller = Account.generate()

# Build multi-agent transaction
payload = EntryFunction.natural(
    "0x1::marketplace",
    "purchase_nft",
    [],
    [seller.address(), 123]
)

# Create and sign with both accounts
signed_txn = client.create_multi_agent_bcs_transaction(
    buyer, [seller], payload
)

tx_hash = client.submit_bcs_transaction(signed_txn)
client.wait_for_transaction(tx_hash)
```

## Real-World Use Cases

1. **NFT Marketplaces**: Execute atomic NFT sales where the buyer transfers payment and seller transfers the NFT in a single transaction, eliminating front-running or partial execution risks.

2. **Atomic Swaps**: Enable trustless peer-to-peer token swaps where both parties exchange assets simultaneously without requiring an intermediary or escrow.

3. **Joint Account Operations**: Implement shared accounts or vaults that require multiple parties to approve withdrawals or significant operations.

4. **Escrow Releases**: Coordinate between buyer, seller, and escrow agent to release funds and assets when conditions are met.

5. **Multi-Party Gaming**: Execute game moves or state transitions that require agreement from multiple players in competitive or cooperative games.

6. **Cross-Protocol Operations**: Coordinate actions across different protocols where multiple protocol administrators must authorize complex operations.

## Advanced Patterns

### Three-Way Transactions

```move
public entry fun escrow_complete(
    buyer: &signer,
    seller: &signer,
    escrow_agent: &signer,
    item_id: u64
) acquires EscrowedItem, Payment {
    // All three parties must sign
    // Agent verifies conditions
    // Buyer gets item
    // Seller gets payment
    // Agent gets fee
}
```

### Conditional Multi-Agent

```move
public entry fun conditional_transfer(
    sender: &signer,
    receiver: &signer,
    amount: u64,
    condition_met: bool
) {
    assert!(condition_met, ECONDITION_NOT_MET);
    // Both parties acknowledge the condition is met
    // Execute transfer
}
```

## Best Practices

**Verify All Signers**: Always validate that all required signers have provided valid signatures before executing critical operations.

**Atomic Operations**: Structure multi-agent transactions to be truly atomic - either all operations succeed or all fail together.

**Clear Responsibilities**: Document which signer pays gas (primary signer) and what each secondary signer authorizes.

**Timeout Mechanisms**: Implement expiration times for multi-agent transaction proposals to prevent indefinite pending states.

**Off-Chain Coordination**: Use off-chain communication channels to coordinate signature collection before submitting the final transaction.

**Gas Estimation**: The primary signer pays all gas fees, so ensure they have sufficient funds for the entire transaction.

**Order Independence**: Design functions so that the order of secondary signers doesn't matter when possible to simplify coordination.

## Signature Collection Flow

1. **Transaction Construction**: Primary signer builds the transaction with all secondary signer addresses
2. **Hash Distribution**: Share the transaction hash with all secondary signers
3. **Signature Collection**: Each party signs the transaction hash independently
4. **Aggregation**: Primary signer collects all signatures
5. **Submission**: Submit the fully-signed transaction to the network
6. **Atomic Execution**: All operations execute or fail together

## Security Considerations

**Signature Verification**: Never submit a multi-agent transaction without verifying all signatures are authentic and match expected signers.

**Transaction Inspection**: All signers should inspect the transaction details before signing to ensure they agree with the operations.

**Replay Protection**: Multi-agent transactions include sequence numbers to prevent replay attacks.

**Partial Signing Attacks**: Protect against scenarios where some signers might try to modify the transaction after others have signed.

**Resource Ownership**: Verify that all signers actually own or control the resources the transaction will modify.

## Comparison with Multi-Sig

Multi-agent transactions differ from multi-sig accounts:

- **Multi-Agent**: Multiple independent accounts coordinate on a single transaction
- **Multi-Sig**: Single account controlled by multiple keys with threshold approval

Multi-agent is better for:

- Peer-to-peer interactions between distinct parties
- Operations involving resources from multiple accounts
- One-time coordinated actions

Multi-sig is better for:

- Shared account management
- Corporate treasury controls
- Ongoing governance of a single account

## Related Concepts

- [Sponsored Transactions](https://www.dwellir.com/docs/aptos/sponsored_transactions) - Separate signer and fee payer
- [Resource Accounts](https://www.dwellir.com/docs/aptos/resource_accounts) - Autonomous contract accounts
- [Key Rotation](https://www.dwellir.com/docs/aptos/key_rotation) - Change account keys
- [Object Model](https://www.dwellir.com/docs/aptos/object_model) - Alternative ownership patterns

---

## object_model

# object_model

The Aptos object model introduces a powerful abstraction for managing complex digital assets with rich composition, flexible ownership, and extensible functionality. Objects provide globally addressable, heterogeneous resources that support ownership hierarchies, reference relationships, and safe composition patterns not easily achievable with traditional Move resources.

## Overview

Objects in Aptos are special on-chain entities identified by unique addresses, combining the benefits of resource safety with flexible ownership and composition capabilities. Unlike traditional resources stored directly under user accounts, objects have their own addresses and can own other objects, creating hierarchical ownership structures ideal for NFTs, composable game items, and complex DeFi positions.

## Core Concepts

### Object Creation

Objects are created with unique addresses and can store multiple heterogeneous resources:

```move
module 0x1::nft_collection {
    use std::string::String;
    use aptos_framework::object::{Self, Object, ConstructorRef};
    use aptos_token_objects::token;
    use aptos_token_objects::collection;

    struct CollectionMetadata has key {
        creator: address,
        description: String,
        max_supply: u64,
        minted: u64
    }

    struct TokenMetadata has key {
        name: String,
        description: String,
        uri: String,
        rarity: u8
    }

    // Create a collection object
    public entry fun create_collection(
        creator: &signer,
        name: String,
        description: String,
        max_supply: u64,
        uri: String
    ) {
        let constructor_ref = collection::create_unlimited_collection(
            creator,
            description,
            name,
            option::none(),
            uri
        );

        let object_signer = object::generate_signer(&constructor_ref);
        move_to(&object_signer, CollectionMetadata {
            creator: signer::address_of(creator),
            description,
            max_supply,
            minted: 0
        });
    }

    // Create an NFT object within the collection
    public entry fun mint_nft(
        creator: &signer,
        collection: String,
        name: String,
        description: String,
        uri: String,
        rarity: u8
    ) {
        let constructor_ref = token::create_named_token(
            creator,
            collection,
            description,
            name,
            option::none(),
            uri
        );

        let object_signer = object::generate_signer(&constructor_ref);
        move_to(&object_signer, TokenMetadata {
            name,
            description,
            uri,
            rarity
        });
    }
}
```

## Key Features

### Object References

Objects can reference other objects safely without ownership transfer:

```move
struct GameCharacter has key {
    name: String,
    level: u64,
    equipped_weapon: Object<Weapon>,  // Reference to weapon object
    inventory: vector<Object<Item>>   // References to item objects
}

public fun equip_weapon(
    character_obj: Object<GameCharacter>,
    weapon_obj: Object<Weapon>
) acquires GameCharacter {
    let character = borrow_global_mut<GameCharacter>(object::object_address(&character_obj));
    character.equipped_weapon = weapon_obj;
}
```

### Ownership Transfer

Objects support flexible ownership patterns:

```move
use aptos_framework::object;

public entry fun transfer_nft(
    owner: &signer,
    nft: Object<TokenMetadata>,
    recipient: address
) {
    // Transfer object ownership
    object::transfer(owner, nft, recipient);
}

public entry fun make_soulbound(creator: &signer, nft: Object<TokenMetadata>) {
    // Disable transfers permanently
    let transfer_ref = object::generate_transfer_ref(creator, nft);
    object::disable_ungated_transfer(&transfer_ref);
}
```

### Object Composition

Objects can own other objects, creating hierarchies:

```move
struct Bundle has key {
    items: vector<Object<Item>>,
    total_value: u64
}

public fun create_bundle(
    creator: &signer,
    item_objects: vector<Object<Item>>
) {
    let constructor_ref = object::create_object(signer::address_of(creator));
    let object_signer = object::generate_signer(&constructor_ref);

    // Transfer items to the bundle object
    let i = 0;
    while (i < vector::length(&item_objects)) {
        let item = *vector::borrow(&item_objects, i);
        object::transfer(creator, item, signer::address_of(&object_signer));
        i = i + 1;
    };

    move_to(&object_signer, Bundle {
        items: item_objects,
        total_value: 0 // Calculate from items
    });
}
```

## Real-World Use Cases

1. **Composable NFTs**: Create NFTs that can own other NFTs, like a character owning equipment, a house containing furniture, or a card deck containing individual cards.

2. **DeFi Positions**: Represent complex financial positions as objects that aggregate multiple assets, track performance, and enable atomic position transfers.

3. **Gaming Assets**: Build rich game systems where items, characters, and locations are objects with properties, inventories, and relationships.

4. **Fractional Ownership**: Create objects representing shared ownership of assets where multiple parties hold stakes in a single valuable item.

5. **Licensing and Royalties**: Implement objects that track usage rights, royalty obligations, and derivative relationships between creative works.

6. **Supply Chain Tracking**: Model physical goods as objects that move through a supply chain, accumulating provenance and certification data.

## Best Practices

**Use Objects for Complex Assets**: Prefer objects over simple resources when assets need ownership transfer, composition, or references to other assets.

**Leverage Object Addresses**: Objects have stable addresses independent of owner, enabling reliable references and off-chain indexing.

**Implement Access Control**: Use object extensions and permissions to control who can modify object properties or transfer ownership.

**Consider Gas Costs**: Object operations involve additional overhead compared to simple resources; balance flexibility with efficiency.

**Plan Ownership Hierarchies**: Design clear ownership structures to prevent circular references and simplify asset management.

**Utilize Events**: Emit events for object creation, transfer, and modification to enable off-chain tracking and indexing.

**Test Composition Patterns**: Thoroughly test complex object hierarchies to ensure proper cleanup and prevent orphaned resources.

## Object Capabilities

Objects support various capabilities through refs:

```move
// Transfer control
let transfer_ref = object::generate_transfer_ref(&constructor_ref);
object::disable_ungated_transfer(&transfer_ref);

// Deletion control
let delete_ref = object::generate_delete_ref(&constructor_ref);
object::delete(delete_ref);

// Extension control
let extend_ref = object::generate_extend_ref(&constructor_ref);
let object_signer = object::generate_signer_for_extending(&extend_ref);
```

## Querying Objects

```move
#[view]
public fun get_owner(obj: Object<TokenMetadata>): address {
    object::owner(obj)
}

#[view]
public fun is_owner(obj: Object<TokenMetadata>, potential_owner: address): bool {
    object::is_owner(obj, potential_owner)
}

#[view]
public fun can_transfer(obj: Object<TokenMetadata>): bool {
    object::ungated_transfer_allowed(obj)
}
```

## Object vs Traditional Resources

**Use Objects When:**

- Assets need to be transferred between users
- Complex composition or hierarchies are required
- Stable addresses independent of owner are beneficial
- References between assets are needed

**Use Traditional Resources When:**

- Simple account-scoped data storage
- No transfer or ownership changes needed
- Minimizing gas costs is critical
- Simple key-value storage suffices

## Related Concepts

- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Traditional resource patterns
- [Multi-Agent Transactions](https://www.dwellir.com/docs/aptos/multi_agent) - Transfer objects atomically
- [View Functions](https://www.dwellir.com/docs/aptos/view_functions) - Query object properties
- [Testing](https://www.dwellir.com/docs/aptos/testing) - Test object composition

---

## orderless_transactions

# orderless_transactions

Orderless transactions on Aptos reduce head-of-line blocking by allowing flexible transaction ordering using explicit nonces instead of strict sequence numbers. This feature enables parallel transaction submission and improves throughput for accounts issuing multiple independent operations simultaneously.

## Overview

Traditional blockchain accounts process transactions in strict sequential order based on sequence numbers, where transaction N+1 cannot execute until transaction N completes. Orderless transactions relax this constraint by using nonces that allow transactions to execute in any order when dependencies permit, significantly improving performance for high-frequency accounts like exchanges, bots, and payment processors.

## How It Works

Instead of requiring sequential processing, orderless transactions use nonces to indicate independence:

```move
// Traditional: Must execute in order 0, 1, 2, 3...
Transaction { sequence_number: 0 }
Transaction { sequence_number: 1 }  // Blocks on 0
Transaction { sequence_number: 2 }  // Blocks on 1

// Orderless: Can execute in any order
Transaction { nonce: 1 }  // Independent
Transaction { nonce: 2 }  // Independent
Transaction { nonce: 3 }  // Independent
```

## Implementation

```typescript
import { Aptos, Account } from "@aptos-labs/ts-sdk";

const aptos = new Aptos();
const account = Account.generate();

// Submit multiple transactions with different nonces
const nonce1 = 100;
const nonce2 = 101;
const nonce3 = 102;

// All can execute in parallel
const tx1 = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: "0x1::coin::transfer",
    functionArguments: [recipient1, 1000]
  },
  options: { nonce: nonce1 }
});

const tx2 = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
    function: "0x1::coin::transfer",
    functionArguments: [recipient2, 2000]
  },
  options: { nonce: nonce2 }
});

// Submit both immediately
await aptos.transaction.submit.simple({ transaction: tx1, senderAuthenticator: auth1 });
await aptos.transaction.submit.simple({ transaction: tx2, senderAuthenticator: auth2 });
```

## Real-World Use Cases

1. **Exchange Operations**: Crypto exchanges can submit thousands of withdrawal transactions simultaneously without waiting for sequential processing, dramatically increasing throughput.

2. **Payment Processors**: Payment platforms can process multiple customer payments in parallel rather than queuing them sequentially.

3. **Bot Operations**: Trading bots and automated market makers can submit multiple independent transactions without head-of-line blocking from slower operations.

4. **Batch Processing**: Applications can submit large batches of independent transactions that execute as capacity permits rather than in strict order.

5. **Multi-User Services**: Services managing operations for multiple users can interleave transactions without artificial ordering constraints.

6. **Retry Logic**: Failed transactions can be retried with new nonces while other transactions continue processing without blocking.

## Best Practices

**Use Unique Nonces**: Ensure each transaction from an account uses a unique nonce to prevent conflicts and rejections.

**Track Nonce Usage**: Maintain a nonce counter or registry to avoid accidentally reusing nonces across concurrent operations.

**Handle Race Conditions**: Implement proper error handling for nonce conflicts that may occur in distributed systems.

**Monitor Nonce Gaps**: Track which nonces have been used to identify failed or pending transactions.

**Set Reasonable Limits**: Don't create excessive nonce gaps as validators may have limits on nonce range acceptance.

**Combine with Sequence Numbers**: Use orderless transactions for truly independent operations while using sequence numbers for dependent chains.

## Limitations

- Nonces must be managed carefully to avoid conflicts
- Not all transaction types support orderless execution
- May require changes to existing transaction submission infrastructure
- Validators may impose limits on maximum nonce values or gaps
- Ordering guarantees between transactions are reduced

## Comparison with Sequential Transactions

**Sequential (Traditional)**

- Guaranteed execution order
- Simpler to reason about dependencies
- Natural retry semantics
- Lower throughput under load

**Orderless (Nonce-based)**

- Higher throughput potential
- Parallel execution capability
- More complex nonce management
- Better for independent operations

## Monitoring and Debugging

```typescript
// Track nonce usage
const usedNonces = new Set<number>();

function getNextNonce(): number {
  let nonce = Math.floor(Math.random() * 1000000);
  while (usedNonces.has(nonce)) {
    nonce = Math.floor(Math.random() * 1000000);
  }
  usedNonces.add(nonce);
  return nonce;
}

// Check transaction status by nonce
async function checkNonceStatus(account: address, nonce: number) {
  // Query blockchain for transaction with specific nonce
}
```

## Related Concepts

- [Aggregator V2](https://www.dwellir.com/docs/aptos/aggregator_v2) - Parallel state updates
- [Sponsored Transactions](https://www.dwellir.com/docs/aptos/sponsored_transactions) - Flexible fee payment
- [Multi-Agent Transactions](https://www.dwellir.com/docs/aptos/multi_agent) - Multi-party coordination

---

## Real-Time Aptos Transaction Streaming

The Aptos Transaction Stream is not generally available, and we have not measured
delivery lag at the head of chain. Email
<support@dwellir.com> to join the early-access list.

# Real-Time Aptos Transaction Streaming

A real-time tail subscribes near the head of the chain and receives finalized
transactions as blocks are produced. It replaces polling loops in indexers,
notification services, dashboards, and trading systems.

Read the [Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) first — it
covers the service definition, request fields, and metering that this page builds on.

## Start a Tail

Omit `starting_version` to begin near the head of chain. Omit `transactions_count`
so the stream runs indefinitely.

```typescript
import { credentials, Metadata } from '@grpc/grpc-js';

const client = new RawDataClient(
  process.env.DWELLIR_APTOS_STREAM_ENDPOINT, // assigned at onboarding
  credentials.createSsl()
);

const metadata = new Metadata();
metadata.add('x-api-key', process.env.DWELLIR_API_KEY);

// No starting_version   -> begin at the head of chain
// No transactions_count -> unbounded stream
const request = {};

const stream = client.GetTransactions(request, metadata);

stream.on('data', (response) => {
  // Each message is a BATCH, not a single transaction.
  for (const tx of response.transactions) {
    handleTransaction(tx);
  }

  // Advance progress from processed_range, not from the last transaction.
  if (response.processed_range) {
    lastProcessedVersion = BigInt(response.processed_range.last_version);
  }
});

stream.on('error', (error) => {
  console.error('Stream error:', error.code, error.details);
  scheduleReconnect();
});

stream.on('end', () => {
  scheduleReconnect();
});
```

`TransactionsResponse` carries `transactions[]`, `chain_id`, and
`processed_range`. A handler written as `stream.on('data', tx => tx.version)`
reads the batch as though it were a transaction and will silently process nothing
useful. Always iterate `response.transactions`.

## Read a Transaction

Top-level fields come from `aptos.transaction.v1.Transaction`. The hash lives on
`info` and is a `bytes` field:

```typescript
function handleTransaction(tx) {
  const hash = Buffer.from(tx.info.hash).toString('hex');

  console.log({
    version: tx.version,           // string (jstype = JS_STRING)
    hash: `0x${hash}`,
    blockHeight: tx.block_height,
    epoch: tx.epoch,
    type: tx.type,                 // TRANSACTION_TYPE_USER, _BLOCK_METADATA, ...
    success: tx.info.success,
    gasUsed: tx.info.gas_used,
    timestamp: tx.timestamp,       // { seconds, nanos }
  });

  if (tx.type === 'TRANSACTION_TYPE_USER') {
    processUserTransaction(tx.user);
  }
}
```

`version`, `block_height`, `epoch`, and `gas_used` are annotated
`jstype = JS_STRING` upstream, so most JavaScript stubs hand them back as strings.
Convert with `BigInt()` before doing arithmetic.

## Filter on the Server

A head-of-chain tail on Aptos carries every transaction the network produces.
Filtering server-side cuts both the data you parse and the messages you are billed
for, because the filter runs before delivery and before metering.

```typescript
// Successful 0x1::coin::transfer calls only.
const request = {
  transaction_filter: {
    logical_and: {
      filters: [
        { api_filter: { transaction_root_filter: { success: true } } },
        {
          api_filter: {
            user_transaction_filter: {
              payload_filter: {
                entry_function_filter: {
                  address: '0x1',
                  module_name: 'coin',
                  function: 'transfer',
                },
              },
            },
          },
        },
      ],
    },
  },
};
```

`BooleanTransactionFilter` composes three leaf filters — `transaction_root_filter`
(success, transaction type), `user_transaction_filter` (sender, entry function),
and `event_filter` (Move struct type, data substring) — with `logical_and`,
`logical_or`, and `logical_not`.

When a filter removes everything in a version range, the server still emits a
message carrying `processed_range` so you can advance your checkpoint. Those
messages are metered. A narrow filter reduces bytes and parsing work; it does not
reduce message count to zero.

## Track Progress

`processed_range` reports the version span the server covered, including versions
your filter dropped. Checkpointing from it keeps progress moving even during long
runs of non-matching transactions, and it is what you supply as `starting_version`
after a restart.

```typescript
class TailCheckpoint {
  private lastVersion: bigint | null = null;
  private dirty = false;

  observe(response) {
    if (!response.processed_range) return;
    this.lastVersion = BigInt(response.processed_range.last_version);
    this.dirty = true;
  }

  // Flush on an interval rather than per message.
  async flush() {
    if (!this.dirty || this.lastVersion === null) return;
    await db.upsert('stream_checkpoints', {
      name: 'aptos_tail',
      last_version: this.lastVersion.toString(),
      updated_at: new Date(),
    });
    this.dirty = false;
  }

  async resumeVersion(): Promise<bigint | null> {
    const row = await db.findOne('stream_checkpoints', { name: 'aptos_tail' });
    return row ? BigInt(row.last_version) + 1n : null;
  }
}
```

Only checkpoint versions you have fully processed downstream. Recording progress
before the write lands turns a crash into a silent gap.

## Reconnect Without Gaps

Reconnect with `starting_version` set to the version after your last checkpoint.
A reconnect can redeliver versions you already handled, so downstream writes must
be idempotent.

```typescript
class TailManager {
  private attempts = 0;

  async connect() {
    const resumeFrom = await this.checkpoint.resumeVersion();

    // First run has no checkpoint: start at the head.
    const request = resumeFrom === null
      ? {}
      : { starting_version: resumeFrom.toString() };

    const stream = client.GetTransactions(request, metadata);

    stream.on('data', (response) => {
      this.attempts = 0;
      this.handleBatch(response);
    });

    stream.on('error', () => this.scheduleReconnect());
    stream.on('end', () => this.scheduleReconnect());
  }

  private async scheduleReconnect() {
    this.attempts += 1;
    const backoff = Math.min(1000 * 2 ** this.attempts, 30_000);
    const jitter = Math.random() * 0.3 * backoff;
    await sleep(backoff + jitter);
    await this.connect();
  }
}
```

Aptos reaches BFT finality before a transaction enters the stream, so there is no
reorg handling to write. A version you have processed will not be revised.

## Handle Backpressure

`@grpc/grpc-js` emits `data` faster than most consumers can write. Serialize
processing and pause the stream when your queue grows, rather than letting an
unbounded array absorb the difference.

```typescript
const MAX_QUEUE = 500;
const queue = [];
let draining = false;

stream.on('data', (response) => {
  queue.push(response);

  if (queue.length > MAX_QUEUE) {
    stream.pause();
  }

  if (!draining) void drain();
});

async function drain() {
  draining = true;
  while (queue.length > 0) {
    const response = queue.shift();
    for (const tx of response.transactions) {
      await handleTransaction(tx);
    }
    checkpoint.observe(response);

    if (queue.length < MAX_QUEUE / 2) {
      stream.resume();
    }
  }
  draining = false;
}
```

## Expected Message Rate

For an unfiltered tail, the server sends roughly **one message per block**. It does
not wait to fill `batch_size`, so head-of-chain batches are much smaller than the
1000 ceiling and your message rate tracks block production rather than transaction
volume.

Because the billed unit is the message, this is the number to compare against your
existing Sui checkpoint usage when estimating cost. See
[Metering](https://www.dwellir.com/docs/aptos/streaming/overview#metering).

## Monitor the Tail

Track these four signals:

| Signal                  | Why it matters                                                                           |
| ----------------------- | ---------------------------------------------------------------------------------------- |
| Version lag             | Head version minus your last checkpoint. The clearest sign a consumer is falling behind. |
| Messages per second     | Compare against block rate to detect a stalled or throttled stream.                      |
| Time since last message | A silent stream and a healthy quiet period look identical without a threshold.           |
| Reconnect rate          | Rising reconnects usually mean backpressure or rate limiting, not network faults.        |

A tail that stops receiving messages without an error is usually rate limiting. On
Dwellir, plan rate limits apply **per account, not per key**, so a second workload
on the same account can throttle this stream — see
[Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#scope-per-account-not-per-key).

## Related Guides

- [Transaction Stream Overview](https://www.dwellir.com/docs/aptos/streaming/overview) — service definition, request fields, metering
- [Historical Replay](https://www.dwellir.com/docs/aptos/historical_replay) — starting from a stored version
- [Custom Processors](https://www.dwellir.com/docs/aptos/custom_processors) — worker architecture on batch semantics
- [Authentication](https://www.dwellir.com/docs/aptos/authentication) — API key handling

---

## resource_accounts

# resource_accounts

Resource accounts are special autonomous accounts on Aptos that have no private key and can only be controlled by smart contracts. They enable developers to create stable, deterministic addresses for protocols while maintaining programmatic control over account operations, making them essential for DeFi protocols, DAOs, and autonomous systems.

## Overview

Resource accounts solve the problem of protocol-controlled accounts that need stable addresses but shouldn't have private keys that could be lost or compromised. They are created with deterministic addresses derived from a source account and seed, allowing protocols to own assets, publish modules, and execute operations entirely through smart contract logic.

## Creating Resource Accounts

```move
module 0x1::protocol {
    use std::signer;
    use aptos_framework::resource_account;
    use aptos_framework::account;

    struct ResourceAccountCap has key {
        cap: account::SignerCapability
    }

    // Create a resource account during protocol initialization
    public entry fun initialize(deployer: &signer, seed: vector<u8>) {
        // Create resource account with deterministic address
        let (resource_signer, signer_cap) = account::create_resource_account(
            deployer,
            seed
        );

        // Store capability to use resource account later
        move_to(deployer, ResourceAccountCap { cap: signer_cap });

        // Resource account can now hold assets, publish modules
        // Address is deterministic: derived from deployer + seed
    }

    // Use resource account for protocol operations
    public entry fun protocol_transfer(
        amount: u64,
        recipient: address
    ) acquires ResourceAccountCap {
        let cap = borrow_global<ResourceAccountCap>(@deployer);
        let resource_signer = account::create_signer_with_capability(&cap.cap);

        // Resource account executes transfer
        coin::transfer<AptosCoin>(&resource_signer, recipient, amount);
    }
}
```

## Deterministic Addresses

Resource account addresses are deterministically computed:

```move
// Address formula: hash(source_address, seed, 0xFF)
let resource_addr = account::create_resource_address(&source_address, seed);
```

This enables:

- Predictable protocol addresses before deployment
- Consistent addresses across different networks
- Easy verification of protocol authenticity

## Real-World Use Cases

1. **DeFi Protocols**: Create liquidity pools, vaults, and treasury accounts that are controlled by protocol logic rather than private keys, eliminating single points of failure.

2. **DAO Treasuries**: Establish autonomous treasuries where funds can only be moved through governance proposals and smart contract execution.

3. **Escrow Services**: Build trustless escrow systems where locked assets are held by resource accounts with programmatic release conditions.

4. **Protocol Upgrades**: Deploy protocol modules to resource accounts, enabling controlled upgrade paths through governance rather than admin keys.

5. **Cross-Chain Bridges**: Operate bridge accounts that custody locked assets with release controlled by multi-sig validation logic.

6. **Automated Market Makers**: Run AMM contracts where liquidity provider funds are held in resource accounts managed by protocol mathematics.

## Best Practices

**Secure Signer Capabilities**: Store `SignerCapability` in a protected resource with appropriate access controls. Never expose it directly.

**Use Meaningful Seeds**: Choose descriptive seeds that indicate the resource account's purpose (e.g., b"liquidity\_pool\_v2").

**Implement Access Control**: Add authorization logic to functions that use resource account capabilities.

**Test Address Generation**: Verify resource account addresses are computed correctly before mainnet deployment.

**Document Ownership**: Clearly document which modules control which resource accounts for auditing and verification.

**Capability Rotation**: Consider patterns for safely transferring or revoking resource account control if needed.

**Avoid Seed Collisions**: Use unique seeds to prevent accidentally creating multiple resource accounts at the same address.

## Advanced Patterns

### Multi-Tier Resource Accounts

```move
// Create hierarchy of resource accounts
public fun create_protocol_structure(creator: &signer) {
    let (treasury_signer, treasury_cap) = account::create_resource_account(
        creator,
        b"treasury"
    );

    let (rewards_signer, rewards_cap) = account::create_resource_account(
        creator,
        b"rewards"
    );

    let (insurance_signer, insurance_cap) = account::create_resource_account(
        creator,
        b"insurance"
    );

    // Store capabilities for different protocol functions
}
```

### Controlled Capability Distribution

```move
struct GovernanceCap has key {
    treasury_cap: account::SignerCapability,
    withdraw_limit: u64,
    last_withdraw: u64
}

public fun governed_withdraw(
    amount: u64,
    recipient: address
) acquires GovernanceCap {
    let gov = borrow_global_mut<GovernanceCap>(@governance);

    // Enforce time-locks and limits
    assert!(amount <= gov.withdraw_limit, EEXCEEDS_LIMIT);

    let resource_signer = account::create_signer_with_capability(&gov.treasury_cap);
    coin::transfer(&resource_signer, recipient, amount);

    gov.last_withdraw = timestamp::now_seconds();
}
```

## Security Considerations

**Capability Storage**: The `SignerCapability` is extremely powerful - treat it like a master private key and protect it appropriately.

**Access Control**: Implement robust access control for any function that uses resource account capabilities.

**Upgrade Safety**: If resource accounts publish modules, carefully manage upgrade policies to prevent malicious changes.

**Resource Exhaustion**: Resource accounts need gas for operations, so ensure they maintain sufficient APT balances.

**Deterministic Generation**: Understand that anyone can compute your resource account address from the source and seed.

## Querying Resource Accounts

```move
#[view]
public fun get_resource_account_address(source: address, seed: vector<u8>): address {
    account::create_resource_address(&source, seed)
}

#[view]
public fun get_protocol_treasury(): address {
    account::create_resource_address(&@deployer, b"treasury")
}
```

## Comparison with Regular Accounts

**Resource Accounts:**

- No private key
- Controlled by smart contracts
- Deterministic addresses
- Perfect for protocols

**Regular Accounts:**

- Have private keys
- User-controlled
- Random addresses
- For individual users

## Related Concepts

- [Multi-Agent Transactions](https://www.dwellir.com/docs/aptos/multi_agent) - Coordinate with resource accounts
- [Sponsored Transactions](https://www.dwellir.com/docs/aptos/sponsored_transactions) - Pay gas for resource accounts
- [Module Structure](https://www.dwellir.com/docs/aptos/module_structure) - Deploy modules to resource accounts
- [Key Rotation](https://www.dwellir.com/docs/aptos/key_rotation) - Not applicable to resource accounts

---

## resource_management

# resource_management

Resource management is one of Move's most distinctive and powerful features, providing built-in safety guarantees that prevent common blockchain vulnerabilities. Move's resource model ensures that digital assets cannot be copied, accidentally lost, or double-spent through compiler-enforced linear type semantics and explicit resource handling patterns.

## Overview

Resources in Move are special types marked with the `key` ability that represent digital assets or critical state. Unlike regular data structures, resources have strict lifecycle rules: they cannot be copied or implicitly destroyed, must be explicitly moved between storage locations, and can only exist in one place at a time. This linear type system eliminates entire classes of vulnerabilities that plague other blockchain platforms.

## Resource Lifecycle

Resources follow a strict lifecycle from creation to destruction:

```move
module 0x1::resource_example {
    use std::signer;

    // Resource definition - key ability required for global storage
    struct Vault has key {
        balance: u64,
        owner: address
    }

    // Creating a resource
    public entry fun create_vault(account: &signer, initial_balance: u64) {
        let vault = Vault {
            balance: initial_balance,
            owner: signer::address_of(account)
        };
        // Move resource into global storage
        move_to(account, vault);
    }

    // Accessing a resource - requires acquires annotation
    public fun get_balance(addr: address): u64 acquires Vault {
        let vault_ref = borrow_global<Vault>(addr);
        vault_ref.balance
    }

    // Modifying a resource
    public entry fun deposit(account: &signer, amount: u64) acquires Vault {
        let addr = signer::address_of(account);
        let vault_ref = borrow_global_mut<Vault>(addr);
        vault_ref.balance = vault_ref.balance + amount;
    }

    // Moving resource out of storage
    public entry fun destroy_vault(account: &signer) acquires Vault {
        let addr = signer::address_of(account);
        let Vault { balance: _, owner: _ } = move_from<Vault>(addr);
        // Resource is destructured and destroyed
    }
}
```

## Acquires Annotation

The `acquires` keyword is mandatory for functions that access global resources. It serves both as documentation and as a compiler check to prevent reentrancy vulnerabilities:

```move
// Function that reads from one resource and writes to another
public fun transfer_between_vaults(
    from: address,
    to: address,
    amount: u64
) acquires Vault {
    let from_vault = borrow_global_mut<Vault>(from);
    from_vault.balance = from_vault.balance - amount;

    let to_vault = borrow_global_mut<Vault>(to);
    to_vault.balance = to_vault.balance + amount;
}

// Multiple resource types require listing all
public fun complex_operation(addr: address) acquires Vault, UserProfile, Settings {
    // Can access all three resource types
}
```

## Resource Patterns

### Capability Pattern

Use capability resources to control access to privileged operations:

```move
struct MintCapability has key, store {
    total_minted: u64
}

public fun mint_with_cap(
    cap: &mut MintCapability,
    recipient: address,
    amount: u64
) {
    cap.total_minted = cap.total_minted + amount;
    // Mint logic here
}
```

### Witness Pattern

Use one-time witnesses for initialization guarantees:

```move
struct COIN has drop {}

public fun initialize(witness: COIN, account: &signer) {
    // Can only be called once because witness is consumed
}
```

### Hot Potato Pattern

Create types without drop ability to force handling:

```move
struct Receipt {
    amount: u64,
    must_be_consumed: bool
}

public fun create_receipt(): Receipt {
    Receipt { amount: 100, must_be_consumed: true }
}

public fun consume_receipt(receipt: Receipt) {
    let Receipt { amount: _, must_be_consumed: _ } = receipt;
}
```

## Real-World Use Cases

1. **Token Implementations**: Manage token balances as resources to guarantee conservation of supply and prevent unauthorized minting or burning through compiler-enforced linearity.

2. **NFT Ownership**: Represent unique digital assets as resources that cannot be duplicated, ensuring true scarcity and provable ownership on-chain.

3. **Vault Systems**: Build secure storage mechanisms where assets can only be accessed by authorized parties, leveraging resource semantics for safety.

4. **Permission Systems**: Create capability resources that grant specific permissions, ensuring that access rights cannot be forged or duplicated.

5. **Escrow Services**: Hold resources in escrow with guaranteed atomic transfers, where assets must either complete the full transfer or remain in the original location.

6. **Gaming Assets**: Represent in-game items as resources with unique properties that cannot be duplicated or destroyed outside intended game mechanics.

## Best Practices

**Always Document Acquires**: Explicitly list all resource types a function accesses in the acquires clause, even when it seems obvious. This helps prevent subtle bugs.

**Check Resource Existence**: Use `exists<T>(address)` before borrowing resources to handle cases where resources might not be initialized.

**Avoid Cross-Module Resource Access**: Design modules to manage their own resources rather than accessing resources defined in other modules when possible.

**Use Immutable Borrows**: Prefer `borrow_global` over `borrow_global_mut` when only reading data to reduce potential for concurrent access issues.

**Structured Destruction**: When moving resources out of storage, always destructure them completely to ensure all fields are properly handled.

**Resource Initialization**: Provide clear initialization functions and document preconditions for resource creation to prevent misuse.

**Capability Distribution**: Carefully control how and when capability resources are created and distributed to maintain system security.

## Common Patterns

```move
// Check-then-access pattern
if (exists<Vault>(addr)) {
    let vault = borrow_global<Vault>(addr);
    // Use vault
};

// Modify with validation
public entry fun safe_withdraw(account: &signer, amount: u64) acquires Vault {
    let addr = signer::address_of(account);
    assert!(exists<Vault>(addr), EVAULT_NOT_FOUND);

    let vault = borrow_global_mut<Vault>(addr);
    assert!(vault.balance >= amount, EINSUFFICIENT_BALANCE);
    vault.balance = vault.balance - amount;
}
```

## Related Concepts

- [Module Structure](https://www.dwellir.com/docs/aptos/module_structure) - Organize resource definitions effectively
- [Formal Verification](https://www.dwellir.com/docs/aptos/formal_verification) - Prove resource invariants mathematically
- [Object Model](https://www.dwellir.com/docs/aptos/object_model) - Alternative resource composition approach
- [Testing](https://www.dwellir.com/docs/aptos/testing) - Test resource lifecycle operations

---

## spec

# spec

## Overview

Open the Aptos REST API explorer page served by the node. On Dwellir Aptos mainnet, `/v1/spec` returns an interactive Stoplight HTML document rather than a raw JSON or YAML OpenAPI payload.

## Endpoint

`GET /v1/spec`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Open the interactive explorer page
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/spec" \
      -H "Accept: application/json"

    # Save the HTML explorer page locally
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/spec" \
      -H "Accept: application/json" \
      -o aptos-spec.html
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (200) Returns an HTML document (`content-type: text/html; charset=utf-8`) that embeds the Aptos Node API explorer: ```html <!doctype html> <html lang="en"> <head> <title>Aptos Node API</title> <script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script> </head> <body> <elements-api apiDescriptionUrl="/openapi.yaml"></elements-api> </body> </html> ``` Treat this endpoint as a human-facing interactive explorer page, not a machine-readable artifact for direct SDK generation.

## Successful Response

```html
<!doctype html>
<html lang="en">
  <head>
    <title>Aptos Node API</title>
    <script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
  </head>
  <body>
    <elements-api apiDescriptionUrl="/openapi.yaml"></elements-api>
  </body>
</html>
```

## Code Examples

cURL
Python
TypeScript

```bash
# Open the interactive explorer page
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/spec" \
  -H "Accept: application/json"

# Save the HTML explorer page locally
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/spec" \
  -H "Accept: application/json" \
  -o aptos-spec.html
```

```python
import requests
response = requests.get(
    "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/spec",
    headers={"Accept": "application/json"}
)
print(response.headers["content-type"])
html = response.text

# Save the Stoplight explorer page
with open("aptos-spec.html", "w") as f:
    f.write(html)
```

```typescript
// Fetch the explorer page
const response = await fetch(
  "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/spec",
  { headers: { "Accept": "application/json" } }
);
const html = await response.text();
console.log(response.headers.get("content-type"));
console.log(html.includes("Aptos Node API"));
```

## Integration with Development Tools

### Browser Explorer

Use the returned page as a human-facing explorer in a browser tab. If you need machine-readable schemas for code generation, source them from a verified raw spec artifact rather than `/v1/spec`.

## Use Cases

1. **Interactive API Exploration**: Open the embedded Stoplight page to browse endpoints, request examples, and schemas manually.
2. **Onboarding and Support**: Share one URL with developers who need to inspect the REST surface without installing extra tooling.
3. **Quick Endpoint Discovery**: Verify paths, parameters, and response descriptions while debugging integrations.

## Best Practices

**Version Pinning**: The specification matches the API version of the node you are querying. For production applications, pin to a specific specification version and test thoroughly before upgrading.

**Caching**: The specification changes only when the node software is upgraded. Cache it locally during development rather than fetching on every build. Re-fetch when you detect node version changes via the `git_hash` field in ledger info.

**Format Selection**: On Dwellir Aptos mainnet, `/v1/spec` returns HTML even when you request JSON. Do not treat this endpoint as a raw OpenAPI download target for parsers or code generators.

## Performance Considerations

The explorer document is moderately large and rarely changes. Cache it locally if you need an offline copy for documentation review.

This endpoint does not touch blockchain state. Response times are primarily driven by serving the static HTML explorer page and its embedded assets.

Avoid fetching the explorer at application runtime unless you are explicitly linking users to documentation.

## Related Resources

- Aptos TypeScript SDK (`@aptos-labs/ts-sdk`) uses this specification as a basis for type definitions
- OpenAPI Generator documentation at openapi-generator.tech
- OpenAPI 3.0 specification documentation at swagger.io
- `/v1` - Get ledger info including node software version

---

## sponsored_transactions

# sponsored_transactions

Sponsored transactions enable gas fee delegation on Aptos, allowing one account (the sponsor) to pay transaction fees for another account (the user). This feature is crucial for onboarding new users, providing gasless experiences, and building accessible dApps that don't require users to hold native tokens before interacting with applications.

## Overview

Traditional blockchain interactions require users to hold native tokens (APT on Aptos) to pay gas fees, creating a significant onboarding barrier. Sponsored transactions separate the transaction sender from the fee payer, enabling applications, DAOs, or services to subsidize user transactions while maintaining proper authentication and authorization.

## How Sponsored Transactions Work

A sponsored transaction involves three parties:

1. **User (Sender)**: Signs the transaction to authorize their operations
2. **Sponsor (Fee Payer)**: Pays gas fees and signs to authorize payment
3. **Network**: Validates both signatures and executes the transaction

```typescript
import { Aptos, Account } from "@aptos-labs/ts-sdk";

const aptos = new Aptos();

// User who wants to perform an operation but has no APT
const user = Account.generate();

// Sponsor who will pay the gas fees
const sponsor = Account.generate(); // Must have APT

// Build sponsored transaction
const transaction = await aptos.transaction.build.simple({
  sender: user.accountAddress,
  data: {
    function: "0x1::aptos_account::transfer",
    functionArguments: [recipientAddress, 1000]
  },
  withFeePayer: true
});

// User signs their part
const userAuth = aptos.transaction.sign({
  signer: user,
  transaction
});

// Sponsor signs to pay fees
const sponsorAuth = aptos.transaction.signAsFeePayer({
  signer: sponsor,
  transaction
});

// Submit with both signatures
const committedTxn = await aptos.transaction.submit.simple({
  transaction,
  senderAuthenticator: userAuth,
  feePayerAuthenticator: sponsorAuth
});

await aptos.waitForTransaction({ transactionHash: committedTxn.hash });
```

## Move Implementation

```move
module 0x1::sponsored_service {
    use std::signer;
    use aptos_framework::coin;
    use aptos_framework::aptos_coin::AptosCoin;

    struct SponsorshipConfig has key {
        enabled: bool,
        daily_limit: u64,
        per_user_limit: u64
    }

    struct UserQuota has key {
        used_today: u64,
        last_reset: u64
    }

    // User function that can be sponsored
    public entry fun perform_action(user: &signer, data: vector<u8>) {
        // User's actual operation
        // Gas will be paid by sponsor, not user
    }

    // Sponsor checks if they should sponsor this user
    public entry fun check_sponsorship_eligibility(
        user: address,
        estimated_gas: u64
    ): bool acquires UserQuota, SponsorshipConfig {
        let config = borrow_global<SponsorshipConfig>(@sponsor);
        if (!config.enabled) return false;

        if (!exists<UserQuota>(user)) return true;

        let quota = borrow_global<UserQuota>(user);
        quota.used_today + estimated_gas <= config.per_user_limit
    }
}
```

## Real-World Use Cases

1. **User Onboarding**: Let new users interact with your dApp immediately without requiring them to acquire APT first, dramatically reducing onboarding friction.

2. **Gaming Applications**: Sponsor in-game transactions so players can play without worrying about gas fees, creating a seamless gaming experience.

3. **Social Media dApps**: Enable users to post, like, and interact on blockchain social platforms without paying gas for each action.

4. **Enterprise Applications**: Corporations can sponsor transactions for their employees or customers, internalizing blockchain interaction costs.

5. **Loyalty Programs**: Reward loyal users by sponsoring their transactions as a benefit, similar to traditional fee waivers.

6. **Micropayments**: Enable micro-transaction use cases where gas fees would otherwise be prohibitively expensive relative to transaction value.

## Best Practices

**Implement Rate Limiting**: Protect sponsors from abuse by implementing per-user quotas, daily limits, and velocity checks.

**Verify User Intent**: Ensure the sponsored transaction represents genuine user intent and hasn't been manipulated.

**Gas Estimation**: Accurately estimate gas costs before sponsoring to prevent unexpected costs and set appropriate budgets.

**Conditional Sponsorship**: Only sponsor transactions that meet specific criteria (new users, specific functions, within limits).

**Monitor Costs**: Track total sponsorship costs and set alerts for unusual patterns or excessive spending.

**Graceful Degradation**: Have fallback options if sponsorship limits are reached so users can still complete transactions.

**Transparent Terms**: Clearly communicate sponsorship terms, limits, and conditions to users.

## Advanced Sponsorship Patterns

### Conditional Sponsorship

```typescript
async function conditionalSponsor(
  user: Account,
  transaction: any,
  sponsor: Account
): Promise<boolean> {
  // Check if user qualifies for sponsorship
  const userTxCount = await getUserTransactionCount(user.accountAddress);
  const isNewUser = userTxCount < 10;

  if (isNewUser) {
    // Sponsor new users
    return true;
  }

  // Check if user has loyalty points
  const loyaltyPoints = await getLoyaltyPoints(user.accountAddress);
  if (loyaltyPoints > 100) {
    // Sponsor loyal users
    return true;
  }

  return false; // User must pay own fees
}
```

### Tiered Sponsorship

```move
struct TieredSponsorship has key {
    bronze_limit: u64,  // Sponsor up to X gas
    silver_limit: u64,  // Sponsor up to Y gas
    gold_limit: u64,    // Sponsor up to Z gas
}

public fun get_user_tier(user: address): u8 {
    // Determine user tier based on activity, holdings, etc.
    1 // Bronze
}
```

### Pooled Sponsorship

```move
struct SponsorshipPool has key {
    contributors: vector<address>,
    total_funds: u64,
    used_funds: u64,
}

public fun contribute_to_pool(contributor: &signer, amount: u64) {
    // Add funds to sponsorship pool
    // Multiple parties share sponsorship costs
}
```

## Cost Management

```typescript
// Track sponsorship costs
interface SponsorshipMetrics {
  totalSponsored: number;
  transactionsSponsored: number;
  averageCostPerTx: number;
  dailyBudget: number;
  remainingBudget: number;
}

async function checkBudget(sponsor: Account): Promise<boolean> {
  const metrics = await getSponsorshipMetrics(sponsor.accountAddress);
  return metrics.remainingBudget > metrics.averageCostPerTx;
}
```

## Security Considerations

**Sybil Resistance**: Implement mechanisms to prevent users from creating multiple accounts to exploit sponsorship limits.

**Validation Before Signing**: Sponsors must validate transaction contents before signing to prevent sponsoring malicious operations.

**Budget Controls**: Set strict budget limits and alerts to prevent sponsorship pool depletion.

**Abuse Prevention**: Monitor for unusual patterns that might indicate coordinated abuse of sponsorship systems.

**Emergency Shutdown**: Implement ability to quickly disable sponsorship if abuse is detected.

## Monitoring and Analytics

```typescript
// Track sponsorship metrics
async function trackSponsorship(txHash: string, sponsor: address, user: address, gasPaid: number) {
  await database.insert({
    timestamp: Date.now(),
    txHash,
    sponsor,
    user,
    gasPaid,
    type: 'sponsored_transaction'
  });

  await updateDailyMetrics(sponsor);
  await checkAbusePatterns(user);
}
```

## Related Concepts

- [Multi-Agent Transactions](https://www.dwellir.com/docs/aptos/multi_agent) - Multiple signers in transactions
- [Resource Accounts](https://www.dwellir.com/docs/aptos/resource_accounts) - Programmatic transaction execution
- [Key Rotation](https://www.dwellir.com/docs/aptos/key_rotation) - Sponsor key management
- [Orderless Transactions](https://www.dwellir.com/docs/aptos/orderless_transactions) - High-throughput sponsorship

---

## Aptos Transaction Stream - gRPC Overview

The Aptos Transaction Stream is not generally available. Endpoint hostname and
API-key handling are assigned during onboarding, and we have not published
delivery-lag figures because the service is not yet running in production.
Email <support@dwellir.com> to join the early-access
list.

# Aptos Transaction Stream - gRPC Overview

Dwellir's Aptos Transaction Stream is a server-streaming gRPC service that
delivers finalized transactions in version order without polling. It is aimed at
indexers, analytics backends, trading systems, and monitoring pipelines that need
a continuous feed rather than repeated REST requests.

## Service Definition

The service is the **standard upstream Aptos indexer gRPC API**. There is no
Dwellir-specific service, wrapper, or message type.

|               |                                                                                                                                                                                                                                                                                                                                                                                                           |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Service**   | `aptos.indexer.v1.RawData`                                                                                                                                                                                                                                                                                                                                                                                |
| **Method**    | `GetTransactions`                                                                                                                                                                                                                                                                                                                                                                                         |
| **Type**      | Server-streaming RPC                                                                                                                                                                                                                                                                                                                                                                                      |
| **Protobufs** | [`aptos/indexer/v1/raw_data.proto`](https://github.com/aptos-labs/aptos-core/blob/main/protos/proto/aptos/indexer/v1/raw_data.proto), [`filter.proto`](https://github.com/aptos-labs/aptos-core/blob/main/protos/proto/aptos/indexer/v1/filter.proto), [`aptos/transaction/v1/transaction.proto`](https://github.com/aptos-labs/aptos-core/blob/main/protos/proto/aptos/transaction/v1/transaction.proto) |

Generate your client stubs from the upstream `aptos-core` protos. If you already
vendor them for another provider, those are the correct definitions and no change
is needed.

```proto
service RawData {
  rpc GetTransactions(GetTransactionsRequest) returns (stream TransactionsResponse);
}
```

Earlier versions of these docs showed a `TransactionStreamClient` class, a
`subscribe()` method, and a `stream.aptos.dwellir.com` host. None of those exist.
The correct client is the generated `RawData` stub, the correct call is
`GetTransactions`, and the endpoint is assigned at onboarding.

## Request

```proto
message GetTransactionsRequest {
  optional uint64 starting_version = 1;
  optional uint64 transactions_count = 2;
  optional uint64 batch_size = 3;
  optional BooleanTransactionFilter transaction_filter = 4;
}
```

| Field                | Behaviour                                                                                      |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `starting_version`   | Ledger version to start from. Omit to start near the head of chain.                            |
| `transactions_count` | Stop after this many transactions. Omit for an unbounded stream.                               |
| `batch_size`         | Transactions per `TransactionsResponse`. Defaults to 1000. Values above 1000 are **rejected**. |
| `transaction_filter` | Server-side filter. Non-matching transactions are never sent.                                  |

There are no `includeEvents`, `includeChanges`, or field-mask options. Every
transaction is delivered in full, and filtering is the only way to reduce what
crosses the wire.

## Response

Each message on the stream is a **batch**, not a single transaction:

```proto
message TransactionsResponse {
  repeated aptos.transaction.v1.Transaction transactions = 1;
  optional uint64 chain_id = 2;
  optional ProcessedRange processed_range = 3;
}

message ProcessedRange {
  uint64 first_version = 1;
  uint64 last_version = 2;
}
```

Your `data` handler receives a `TransactionsResponse` and must iterate
`response.transactions`. Treating the message itself as a transaction is the most
common integration mistake.

`processed_range` reports the version span the server covered while producing the
message, including versions that your filter removed. Use it — not the last
transaction version — to advance your checkpoint, so a filtered stream does not
appear to stall across long runs of non-matching transactions.

`Transaction.info.hash` is a `bytes` field, not a hex string. Hex-encode it before
logging or comparing against explorer output. Useful top-level fields are
`version`, `timestamp`, `epoch`, `block_height`, `type`, and `info`.

## Server-Side Filtering

`transaction_filter` is evaluated on the node. Transactions that do not match are
never serialized, never sent, and never metered. This is the main lever for both
latency and cost.

`BooleanTransactionFilter` composes `api_filter` leaves with `logical_and`,
`logical_or`, and `logical_not`:

```proto
message APIFilter {
  oneof filter {
    TransactionRootFilter transaction_root_filter = 1;  // success, transaction_type
    UserTransactionFilter user_transaction_filter = 2;  // sender, entry function
    EventFilter event_filter = 3;                       // struct type, data substring
  }
}
```

A filter for successful user transactions calling a specific entry function:

```typescript
const transactionFilter = {
  logical_and: {
    filters: [
      { api_filter: { transaction_root_filter: { success: true } } },
      {
        api_filter: {
          user_transaction_filter: {
            payload_filter: {
              entry_function_filter: {
                address: '0x1',
                module_name: 'coin',
                function: 'transfer',
              },
            },
          },
        },
      },
    ],
  },
};
```

Sui's `SubscribeCheckpoints` has no server-side filter, so our
[Sui gRPC docs](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) tell you to
filter client-side. Aptos is the opposite: filter on the server, because filtering
is what keeps transactions off your bill.

## Connection and Authentication

The endpoint hostname is assigned when your account is provisioned for the stream.
Connect over TLS on port 443 and pass your existing Dwellir dashboard API key as
gRPC metadata:

```typescript
import { credentials, Metadata } from '@grpc/grpc-js';

const metadata = new Metadata();
metadata.add('x-api-key', process.env.DWELLIR_API_KEY);

const client = new RawDataClient(
  process.env.DWELLIR_APTOS_STREAM_ENDPOINT, // assigned at onboarding
  credentials.createSsl()
);

const stream = client.GetTransactions(request, metadata);
```

There is no separate streaming credential — the stream uses the same key as your
other Dwellir endpoints. See [Authentication](https://www.dwellir.com/docs/aptos/authentication) for the
full details, including how gRPC metadata differs from the key-in-path form used
by the Aptos REST and GraphQL endpoints.

## Metering

The billed unit is the **`TransactionsResponse` message**, consistent with how we
meter Sui gRPC per delivered checkpoint.

- `transaction_filter` is applied **before** metering. Filtered-out transactions
  are neither delivered nor counted.
- A filtered stream still emits progress messages carrying `processed_range` for
  the versions it dropped. **Those messages are billed.**
- At the head of chain, batches are far smaller than the 1000 ceiling, because the
  server sends roughly one message per block rather than waiting to fill a batch.
  Message counts at the tail are therefore driven by block rate, not by
  `batch_size`.

For an unfiltered head-of-chain tail, plan on approximately one message per block.
We will provide exact metering in writing before you commit to the stream.

## Rate Limits

- **No cap on concurrent subscriptions per key.**
- Your plan's rate limit applies per delivered message.
- **Rate limits are scoped per account, not per key.** A stream added to an
  account already running other workloads draws from the same budget. See
  [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#scope-per-account-not-per-key).

Because the limit is per account, a busy Aptos tail can throttle unrelated
production traffic on the same account — including a Sui gRPC subscription. If
the two workloads must not compete, separate them onto different accounts or size
the plan for their combined message rate before going live.

## Region

Aptos is served from Sweden, on the same ingress as our Sui endpoints. If you
already run close to that region for Sui, the Aptos stream lands in the same place.

We have not published p50/p95/p99 delivery lag at the head of chain. The service
is not in production, so the figures do not exist yet and we would rather say so
than publish an estimate.

## Choosing an Operating Mode

| Goal                 | Approach                                                                                                    |
| -------------------- | ----------------------------------------------------------------------------------------------------------- |
| Live tail only       | Omit `starting_version`. See [Real-Time Streaming](https://www.dwellir.com/docs/aptos/real_time).                                  |
| Backfill or recovery | Set `starting_version` to your last checkpoint. See [Historical Replay](https://www.dwellir.com/docs/aptos/historical_replay).     |
| Catch up, then tail  | One stream from your stored version; it transitions into the live tail on its own once it reaches the head. |

## Implementation Checklist

- Iterate `response.transactions`; never treat a message as a single transaction.
- Persist progress from `processed_range.last_version` so reconnects resume without gaps.
- Make downstream writes idempotent — a reconnect can redeliver a version you already processed.
- Filter server-side wherever possible; it reduces both latency and metered messages.
- Handle backpressure explicitly so a slow consumer does not stall the stream reader.
- Monitor reconnect frequency, version lag, and messages per second.
- Keep REST or GraphQL available for targeted lookups and operator debugging.

## Related Guides

- [Authentication](https://www.dwellir.com/docs/aptos/authentication) — API key handling for gRPC, REST, and GraphQL
- [Real-Time Streaming](https://www.dwellir.com/docs/aptos/real_time) — tailing the head of chain
- [Historical Replay](https://www.dwellir.com/docs/aptos/historical_replay) — backfills and recovery
- [Custom Processors](https://www.dwellir.com/docs/aptos/custom_processors) — worker architecture on batch semantics
- [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits) — plan limits and per-account scope

---

## subscriptions

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# subscriptions

GraphQL subscriptions enable real-time data streaming from the Aptos blockchain, allowing applications to receive instant notifications when on-chain events occur. This feature is essential for responsive user interfaces, live dashboards, trading bots, and any application requiring immediate updates without polling.

## Overview

Unlike traditional queries that fetch data once, subscriptions establish persistent connections that stream updates as blockchain state changes. When a new block is added, transactions are processed, or specific events occur, subscribed clients receive notifications immediately, enabling truly reactive blockchain applications.

## Core Subscription Patterns

### New Transactions

```graphql
subscription NewTransactions($address: String!) {
  user_transactions(
    where: {
      _or: [
        { sender: { _eq: $address } },
        { receiver: { _eq: $address } }
      ]
    },
    order_by: { version: desc },
    limit: 1
  ) {
    hash
    sender
    version
    success
    gas_used
    timestamp
  }
}
```

### Balance Changes

```graphql
subscription BalanceUpdates($owner: String!, $asset_type: String!) {
  current_fungible_asset_balances(
    where: {
      owner_address: { _eq: $owner },
      asset_type: { _eq: $asset_type }
    }
  ) {
    amount
    last_transaction_version
    last_transaction_timestamp
  }
}
```

### NFT Transfers

```graphql
subscription NftActivity($collection: String!) {
  token_activities_v2(
    where: {
      token_data: {
        collection_id: { _eq: $collection }
      }
    },
    order_by: { transaction_version: desc },
    limit: 1
  ) {
    transaction_version
    from_address
    to_address
    token_data_id
    type
    transaction_timestamp
  }
}
```

### New Blocks

```graphql
subscription NewBlocks {
  ledger_infos(
    order_by: { version: desc },
    limit: 1
  ) {
    chain_id
    version
    block_height
    epoch
    block_timestamp
  }
}
```

### Event Monitoring

```graphql
subscription EventStream($address: String!, $event_type: String!) {
  events(
    where: {
      account_address: { _eq: $address },
      type: { _eq: $event_type }
    },
    order_by: { transaction_version: desc },
    limit: 1
  ) {
    sequence_number
    type
    data
    transaction_version
    transaction_timestamp
  }
}
```

## Real-World Use Cases

1. **Live Wallets**: Update balances, transaction histories, and token holdings in real-time as blockchain state changes without manual refreshing.

2. **Trading Interfaces**: Stream price updates, order fills, and liquidity changes instantly for responsive trading experiences on DEXes.

3. **Notification Systems**: Alert users immediately when they receive payments, NFT transfers, or other important on-chain events.

4. **Live Dashboards**: Display real-time protocol metrics, transaction volumes, active users, and other statistics with instant updates.

5. **Gaming Applications**: Stream game state changes, item transfers, and player actions in real-time for interactive blockchain games.

6. **Monitoring Tools**: Track smart contract interactions, detect anomalies, and monitor system health with instant event notifications.

## Best Practices

**Handle Reconnections**: Implement automatic reconnection logic with exponential backoff when subscription connections drop.

**Manage Connection Limits**: Be aware of concurrent subscription limits and reuse connections where possible.

**Filter Aggressively**: Use precise WHERE clauses to receive only relevant updates and reduce bandwidth usage.

**Implement Debouncing**: For rapid updates, debounce UI updates to prevent overwhelming the interface with changes.

**Fallback to Polling**: Have polling-based fallbacks for environments where WebSocket connections aren't available.

**Validate Events**: Always validate subscription payloads before processing to handle schema changes gracefully.

**Monitor Performance**: Track subscription latency and message rates to ensure responsive user experiences.

## TypeScript Implementation

```typescript
import { ApolloClient, gql, InMemoryCache } from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
import { SubscriptionClient } from "subscriptions-transport-ws";
import ws from "ws";

// Create WebSocket client
const wsClient = new SubscriptionClient(
  "wss://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql",
  {
    reconnect: true,
    connectionParams: {
      headers: {
        "X-API-Key": "YOUR_API_KEY"
      }
    }
  },
  ws
);

const link = new WebSocketLink(wsClient);

const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

// Subscribe to transactions
function subscribeToTransactions(address: string, callback: (tx: any) => void) {
  const subscription = client.subscribe({
    query: gql`
      subscription NewTransactions($address: String!) {
        user_transactions(
          where: {
            _or: [
              { sender: { _eq: $address } },
              { receiver: { _eq: $address } }
            ]
          },
          order_by: { version: desc },
          limit: 1
        ) {
          hash
          sender
          success
          timestamp
        }
      }
    `,
    variables: { address }
  });

  return subscription.subscribe({
    next: (result) => callback(result.data.user_transactions[0]),
    error: (error) => console.error("Subscription error:", error)
  });
}

// Usage
const unsubscribe = subscribeToTransactions("0x123...", (transaction) => {
  console.log("New transaction:", transaction);
  // Update UI with new transaction
});

// Clean up
// unsubscribe();
```

## Advanced Patterns

### Combined Updates

```typescript
// Subscribe to multiple data streams
function subscribeToWallet(address: string) {
  // Transactions
  const txSub = client.subscribe({
    query: TRANSACTION_SUBSCRIPTION,
    variables: { address }
  });

  // Balance changes
  const balanceSub = client.subscribe({
    query: BALANCE_SUBSCRIPTION,
    variables: { address }
  });

  // NFT transfers
  const nftSub = client.subscribe({
    query: NFT_SUBSCRIPTION,
    variables: { address }
  });

  return {
    unsubscribe: () => {
      txSub.unsubscribe();
      balanceSub.unsubscribe();
      nftSub.unsubscribe();
    }
  };
}
```

### Conditional Subscriptions

```typescript
// Only subscribe when needed
let subscription: any = null;

function startMonitoring(address: string) {
  if (subscription) return;

  subscription = subscribeToTransactions(address, (tx) => {
    if (tx.success) {
      notifyUser(`Transaction ${tx.hash} confirmed`);
    }
  });
}

function stopMonitoring() {
  if (subscription) {
    subscription.unsubscribe();
    subscription = null;
  }
}
```

### Debounced Updates

```typescript
import { debounce } from "lodash";

const updateUI = debounce((data: any) => {
  // Update UI with latest data
  render(data);
}, 100);

subscribeToBalances(address, (balance) => {
  updateUI(balance);
});
```

## WebSocket Connection Management

```typescript
// Robust connection handling
class SubscriptionManager {
  private client: SubscriptionClient;
  private subscriptions: Map<string, any> = new Map();

  constructor(url: string) {
    this.client = new SubscriptionClient(url, {
      reconnect: true,
      reconnectionAttempts: 5,
      connectionParams: {
        headers: { "X-API-Key": process.env.API_KEY }
      }
    });

    this.client.onReconnected(() => {
      console.log("Reconnected - resubscribing...");
      this.resubscribeAll();
    });
  }

  subscribe(id: string, query: any, variables: any, callback: Function) {
    const sub = this.client.request({ query, variables }).subscribe({
      next: (data) => callback(data),
      error: (error) => console.error(`Subscription ${id} error:`, error)
    });

    this.subscriptions.set(id, { sub, query, variables, callback });
    return () => this.unsubscribe(id);
  }

  unsubscribe(id: string) {
    const subscription = this.subscriptions.get(id);
    if (subscription) {
      subscription.sub.unsubscribe();
      this.subscriptions.delete(id);
    }
  }

  private resubscribeAll() {
    this.subscriptions.forEach((sub, id) => {
      this.unsubscribe(id);
      this.subscribe(id, sub.query, sub.variables, sub.callback);
    });
  }
}
```

## Related Concepts

- [GraphQL Overview](https://www.dwellir.com/docs/aptos/graphql/overview) - GraphQL API introduction
- [Streaming API](https://www.dwellir.com/docs/aptos/streaming/overview) - Alternative real-time approach
- [Aggregations](https://www.dwellir.com/docs/aptos/aggregations) - Statistical queries
- [Token Activities](https://www.dwellir.com/docs/aptos/token_activities) - Transaction and transfer monitoring

---

## tables_item

# tables_item

## Overview

Read a single value from a Move state table by its key. Tables in Aptos are key-value stores used by smart contracts to store mappings, balances, configurations, and other structured data. This endpoint provides direct access to individual table entries without fetching the entire resource that contains the table.

## Endpoint

`POST /v1/tables/{table_handle}/item`

## Request Parameters

- `table_handle` (`string, required`): Path parameter: Table handle address (obtained from a resource containing a `Table<K, V>` field)
- `ledger_version` (`string, optional`): Query parameter: Read the table item at a historical ledger version
- `key_type` (`string, required`): Request Body: Move type of the table key (e.g., `address`, `u64`, `0x1::string::String`, or a struct type)
- `value_type` (`string, required`): Request Body: Move type of the table value (e.g., `u128`, `bool`, or a struct type)
- `key` (`any, required`): Request Body: The key to look up, encoded as JSON matching the key_type

## Request Example

```json
{
  "key_type": "address",
  "value_type": "u128",
  "key": "0x619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935"
}
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (200) Returns the value from the table, decoded according to the specified `value_type`: For simple types (u128, u64, bool, address): ```json "1234567890" ``` For struct types: ```json { "amount": "1000000", "owner": "0x1", "metadata": { "name": "Token", "symbol": "TKN" } } ``` ### Error Responses | Status | Error Code | Description | | -- | -- | -- | | 400 | invalid_input | Invalid table handle, key type, value type, or key format | | 404 | table_item_not_found | Key does not exist in the table | | 404 | table_not_found | Table handle does not exist on-chain |

## Successful Response

```json
"1234567890"
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid table handle, key type, value type, or key format

### Error 2

- Code: `table_item_not_found`
- Description: Key does not exist in the table

### Error 3

- Code: `table_not_found`
- Description: Table handle does not exist on-chain

## Code Examples

> **Tip:** The handle `0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca` references the on-chain coin conversion map. The key shown here is the BCS-encoded metadata address for Aptos Coin, and the returned `u128` value is the circulating supply in octas.

cURL
Python
TypeScript
Rust

```bash
# Query a simple key-value pair
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca/item" \
  -H "Content-Type: application/json" \
  -d '{"key_type":"address","value_type":"u128","key":"0x619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935"}'

# Query at a historical version
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/0x1b854.../item?ledger_version=50000000" \
  -H "Content-Type: application/json" \
  -d '{"key_type":"address","value_type":"u128","key":"0x619dc..."}'
```

```python
import requests

BASE_URL = "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

# Query a table item
response = requests.post(
    f"{BASE_URL}/tables/0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca/item",
    json={
        "key_type": "address",
        "value_type": "u128",
        "key": "0x619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935"
    }
)
value = response.json()
print(f"Value: {value}")

# Query with a struct key
response = requests.post(
    f"{BASE_URL}/tables/{handle}/item",
    json={
        "key_type": "0x1::string::String",
        "value_type": "0x1::token::TokenData",
        "key": "my_token_name"
    }
)
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Query a table item
const value = await aptos.getTableItem<string>({
  handle: "0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca",
  data: {
    key_type: "address",
    value_type: "u128",
    key: "0x619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935"
  }
});
console.log(`Value: ${value}`);
```

```rust
use aptos_sdk::rest_client::Client;
use serde_json::json;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let value = client.get_table_item(
    "0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca",
    "address",
    "u128",
    "0x619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935",
).await?;
println!("Value: {:?}", value.inner());
```

## Discovering Table Handles

Table handles are not easily discoverable -- they are stored as fields within resources. Here is the typical discovery workflow:

1. **Query the resource** containing the table:
   ```bash
   GET /v1/accounts/{address}/resource/{resource_type}
   ```

2. **Find the table field** in the response. Table fields have a `handle` property:
   ```json
   {
     "type": "0x1::coin::CoinInfo<0x1::aptos_coin::AptosCoin>",
     "data": {
       "supply": {
         "vec": [{
           "aggregator": {
             "vec": [{
               "handle": "0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca",
               "key": "0x619dc29a..."
             }]
           }
         }]
       }
     }
   }
   ```

3. **Use the handle** to query individual table items.

## Use Cases

1. **Token Supply Tracking**: Query coin supply tables to retrieve current circulation, maximum supply, and minting statistics for any fungible asset.

2. **Configuration Lookups**: Access protocol configuration tables for fee parameters, interest rates, oracle addresses, and governance settings.

3. **Mapping Queries**: Retrieve values from key-value mappings stored in Move tables -- user balances, token ownership records, or application-specific data.

4. **State Verification**: Verify specific state values in smart contracts by directly querying table items rather than fetching and parsing entire resources.

5. **Indexer Alternatives**: For simple key-value lookups, table queries can be more efficient than setting up a GraphQL indexer or processing full resource data.

6. **Analytics and Dashboards**: Build analytics dashboards by querying statistical tables maintained by on-chain protocols.

## Best Practices

**Type Accuracy**: Ensure `key_type` and `value_type` exactly match the table's Move type definitions. Even minor differences (such as `u64` vs `u128`) cause deserialization errors.

**Key Encoding**: Keys must be properly formatted for their type. For addresses, use the full 0x-prefixed hex string. For struct keys, provide a JSON object matching the struct's field layout.

**Handle Discovery**: Table handles are opaque addresses that change when the table is recreated. Always discover handles dynamically from the containing resource rather than hardcoding them.

**404 Handling**: A 404 can mean either the table does not exist or the key does not exist in the table. Check the specific error code (`table_not_found` vs `table_item_not_found`) to distinguish these cases.

**Ledger Version**: Use the optional `ledger_version` query parameter to query tables at historical points in time. This enables time-series analysis, state reconstruction, and consistent cross-table reads.

**Caching**: Table values can change with every transaction that modifies them. Cache based on your knowledge of how frequently the specific key is updated -- protocol parameters change rarely, while user balances change with every transfer.

## Performance Considerations

Table item queries use indexed Merkle tree lookups, typically completing in 50-150ms. Performance depends on key complexity and value size. Simple numeric keys and values are fastest.

Tables are implemented using a Jellyfish Merkle tree structure, providing O(log n) lookup time. Even tables with millions of entries respond quickly due to the logarithmic access pattern.

For bulk queries across many keys in the same table, making concurrent requests is more efficient than sequential queries. However, if you need many entries from the same table, consider whether fetching the entire resource and parsing client-side might be more efficient.

## Related Endpoints

- `/v1/tables/{table_handle}/raw_item` - Read raw BCS-encoded table values
- `/v1/accounts/{address}/resource/{type}` - Fetch the resource containing the table handle
- `/v1/accounts/{address}/resources` - List all resources to discover table handles
- `/v1/view` - Alternative for computed lookups that access tables internally

---

## tables_raw_item

# tables_raw_item

## Endpoint

`POST /v1/tables/{table_handle}/raw_item`

## Request Body

```
{
  "key": { "addr": "0x1" },
  "key_type": "vector<u8>",
  "value_type": "vector<u8>"
}
```

## Response

### Success Response (200)

Returns the raw BCS-encoded bytes as a hex string:

```json
{
  "bytes": "0x0123456789abcdef..."
}
```

The bytes must be decoded using BCS deserialization based on the specified `value_type`.

### Error Responses

| Status | Error Code              | Description                         |
| ------ | ----------------------- | ----------------------------------- |
| 400    | invalid\_input          | Invalid table handle, types, or key |
| 404    | table\_item\_not\_found | Key doesn't exist                   |
| 404    | table\_not\_found       | Table doesn't exist                 |

## Code Examples

```bash
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/0xabc/raw_item" \
  -H "Content-Type: application/json" \
  -d '{"key_type":"vector<u8>","value_type":"vector<u8>","key":"0x00"}'
```

Python example with BCS decoding:

```python
import requests
from aptos_sdk import bcs

response = requests.post(
    "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/{handle}/raw_item",
    json={"key_type": "address", "value_type": "u64", "key": "0x1"}
)
raw_bytes = bytes.fromhex(response.json()['bytes'][2:])  # Remove 0x prefix
value = bcs.deserialize(raw_bytes, bcs.uint64)
```

## Use Cases

Raw table queries serve specialized use cases requiring direct BCS access:

1. **Custom Deserialization**: Deserialize complex or custom Move types that aren't supported by the standard JSON API, using language-specific BCS libraries.

2. **Performance Optimization**: For high-throughput applications, BCS deserialization can be faster than JSON parsing, especially for numeric-heavy data.

3. **Type Flexibility**: Query tables without knowing the exact Move type structure, then decode based on discovered schemas or partial type information.

4. **Cross-Language Compatibility**: BCS is the canonical serialization format for Move. Use raw bytes for interoperability between different SDK implementations.

5. **Verification and Hashing**: Compute cryptographic hashes or signatures over the exact on-chain bytes without JSON encoding ambiguities.

6. **Low-Level Debugging**: Inspect raw serialization format to debug encoding issues or verify data integrity.

## Best Practices

**BCS Knowledge Required**: This endpoint requires deep understanding of BCS serialization and Move type layouts. Use the standard `/tables/{handle}/item` endpoint unless you have specific needs for raw bytes.

**Type Specification**: While you must specify `value_type`, the returned bytes are not validated against this type. It's your responsibility to ensure correct deserialization.

**SDK Support**: Use BCS libraries from official SDKs (aptos-sdk for Python, @aptos-labs/ts-sdk for TypeScript) rather than implementing BCS deserialization yourself.

**Hex Encoding**: Response bytes are 0x-prefixed hex strings. Strip the prefix before converting to byte arrays in most languages.

**Performance Trade-offs**: While BCS deserialization can be faster, the overhead of HTTP requests typically dominates. Only use raw queries if you're batch-processing many items.

## Performance Considerations

Performance characteristics are identical to the standard table item endpoint. The difference is purely in response format - JSON vs raw bytes. Response times are typically 50-150ms.

For applications processing millions of table items, the reduced parsing overhead of BCS can save 10-30% CPU time compared to JSON deserialization, but network I/O remains the bottleneck.

---

## testing

# testing

Testing is crucial for building reliable smart contracts on Aptos. Move provides a comprehensive testing framework that supports unit tests, integration tests, and end-to-end testing scenarios. Proper testing helps catch bugs early, validates business logic, and provides confidence when deploying contracts that manage valuable assets.

## Overview

Move's testing framework allows you to write tests directly in your Move source files using the `#[test]` attribute. Tests can interact with the blockchain state, simulate different signers, and validate both success and failure scenarios. The Aptos CLI provides commands to run tests with detailed output and coverage reporting.

## Unit Testing Basics

Unit tests verify individual functions and modules in isolation:

```move
module 0x1::calculator {
    public fun add(a: u64, b: u64): u64 {
        a + b
    }

    public fun divide(a: u64, b: u64): u64 {
        assert!(b != 0, 1); // EDIVIDE_BY_ZERO
        a / b
    }

    #[test]
    fun test_add() {
        assert!(add(2, 3) == 5, 0);
        assert!(add(0, 0) == 0, 0);
        assert!(add(100, 200) == 300, 0);
    }

    #[test]
    fun test_divide() {
        assert!(divide(10, 2) == 5, 0);
        assert!(divide(100, 10) == 10, 0);
    }

    #[test]
    #[expected_failure(abort_code = 1)]
    fun test_divide_by_zero() {
        divide(10, 0); // Should abort with error code 1
    }
}
```

## Testing with Signers

Test functions can receive signer parameters for testing account-specific logic:

```move
module 0x1::vault {
    use std::signer;

    struct Vault has key {
        balance: u64
    }

    public fun create_vault(account: &signer, initial: u64) {
        move_to(account, Vault { balance: initial });
    }

    public fun deposit(account: &signer, amount: u64) acquires Vault {
        let vault = borrow_global_mut<Vault>(signer::address_of(account));
        vault.balance = vault.balance + amount;
    }

    #[test(account = @0x1)]
    fun test_create_vault(account: &signer) {
        create_vault(account, 100);
        assert!(exists<Vault>(@0x1), 0);
    }

    #[test(account = @0x1)]
    fun test_deposit(account: &signer) acquires Vault {
        create_vault(account, 100);
        deposit(account, 50);
        let vault = borrow_global<Vault>(@0x1);
        assert!(vault.balance == 150, 0);
    }

    #[test(account = @0x1)]
    #[expected_failure]
    fun test_double_create_fails(account: &signer) {
        create_vault(account, 100);
        create_vault(account, 200); // Should fail - resource already exists
    }
}
```

## Multi-Account Testing

Test scenarios involving multiple accounts:

```move
#[test(from = @0x1, to = @0x2)]
fun test_transfer(from: &signer, to: &signer) acquires TokenStore {
    // Setup
    initialize(from, 1000);
    initialize(to, 0);

    // Execute transfer
    transfer(from, signer::address_of(to), 100);

    // Verify balances
    assert!(balance_of(@0x1) == 900, 0);
    assert!(balance_of(@0x2) == 100, 0);
}

#[test(alice = @0x1, bob = @0x2, charlie = @0x3)]
fun test_multi_party_transaction(
    alice: &signer,
    bob: &signer,
    charlie: &signer
) acquires TokenStore {
    // Complex multi-account test scenario
}
```

## Testing Events

Validate that events are emitted correctly:

```move
#[test(account = @0x1)]
fun test_transfer_event(account: &signer) acquires TokenStore, EventStore {
    use aptos_framework::event;

    initialize(account, 1000);

    // Get initial event counter
    let event_store = borrow_global<EventStore>(@0x1);
    let initial_count = event::counter(&event_store.transfer_events);

    // Execute operation
    transfer(account, @0x2, 100);

    // Verify event was emitted
    let final_count = event::counter(&event_store.transfer_events);
    assert!(final_count == initial_count + 1, 0);
}
```

## Test Helpers and Setup

Create helper functions for common test scenarios:

```move
#[test_only]
module 0x1::test_helpers {
    use std::signer;
    use 0x1::vault;

    public fun setup_vault(account: &signer, balance: u64) {
        vault::create_vault(account, balance);
    }

    public fun create_test_accounts(): (signer, signer, signer) {
        // Test-only function to create multiple accounts
    }
}

// Use in tests
#[test(account = @0x1)]
fun test_with_helper(account: &signer) {
    test_helpers::setup_vault(account, 100);
    // Continue test
}
```

## Real-World Use Cases

1. **Token Contract Validation**: Test minting, burning, transfers, and balance tracking to ensure token economics work correctly under all conditions.

2. **Access Control Testing**: Verify that privileged functions can only be called by authorized accounts and that unauthorized access attempts fail properly.

3. **Edge Case Coverage**: Test boundary conditions like zero amounts, maximum values, empty collections, and invalid inputs.

4. **Failure Scenario Testing**: Use `#[expected_failure]` to verify that functions abort correctly when given invalid inputs or when preconditions aren't met.

5. **Upgrade Compatibility**: Test that upgraded modules maintain backward compatibility with existing on-chain state and don't break existing functionality.

6. **Integration Testing**: Test interactions between multiple modules to verify that complex workflows operate correctly end-to-end.

## Best Practices

**Test Both Success and Failure**: Write tests for both happy paths and error conditions. Use `#[expected_failure]` to verify error handling.

**Use Descriptive Test Names**: Name tests clearly to indicate what they're testing (e.g., `test_transfer_insufficient_balance_fails`).

**Keep Tests Independent**: Each test should set up its own state and not depend on execution order or state from other tests.

**Test Edge Cases**: Include tests for boundary values, empty inputs, maximum values, and unusual but valid scenarios.

**Use Test-Only Code**: Mark helper functions and modules with `#[test_only]` to prevent them from being included in production builds.

**Deterministic Testing**: Avoid randomness or time-dependent logic in tests to ensure reproducibility.

**Coverage Goals**: Aim for comprehensive coverage of all public functions and critical internal logic paths.

## Running Tests

```bash
# Run all tests in package
aptos move test --package-dir .

# Run tests with coverage
aptos move test --package-dir . --coverage

# Run specific test
aptos move test --package-dir . --filter test_transfer

# Run tests with gas profiling
aptos move test --package-dir . --gas

# Verbose output
aptos move test --package-dir . --verbose
```

## Advanced Testing Patterns

```move
// Property-based testing pattern
#[test]
fun test_add_commutative() {
    let values = vector[1, 5, 10, 50, 100, 1000];
    let i = 0;
    while (i < vector::length(&values)) {
        let j = 0;
        while (j < vector::length(&values)) {
            let a = *vector::borrow(&values, i);
            let b = *vector::borrow(&values, j);
            assert!(add(a, b) == add(b, a), 0);
            j = j + 1;
        };
        i = i + 1;
    }
}

// State machine testing
#[test(account = @0x1)]
fun test_state_transitions(account: &signer) acquires StateMachine {
    initialize(account);
    assert!(get_state(@0x1) == STATE_INITIAL, 0);

    transition_to_active(account);
    assert!(get_state(@0x1) == STATE_ACTIVE, 0);

    transition_to_complete(account);
    assert!(get_state(@0x1) == STATE_COMPLETE, 0);
}
```

## Related Concepts

- [Formal Verification](https://www.dwellir.com/docs/aptos/formal_verification) - Mathematical proofs of correctness
- [Module Structure](https://www.dwellir.com/docs/aptos/module_structure) - Organize code for testability
- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Test resource lifecycle
- [View Functions](https://www.dwellir.com/docs/aptos/view_functions) - Test read-only operations

---

## token_activities

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# token_activities

Token activities tracking provides comprehensive visibility into NFT and token operations on Aptos, including mints, transfers, burns, and marketplace interactions. The GraphQL API enables querying of activity histories, ownership changes, and collection analytics essential for NFT marketplaces, portfolio trackers, and blockchain explorers.

## Overview

Every NFT interaction on Aptos generates events that are indexed and made queryable through GraphQL. Token activities encompass all operations affecting digital assets - from initial minting through transfers, sales, and eventual burning. This data enables applications to display transaction histories, track provenance, analyze trading patterns, and provide real-time notifications for NFT-related events.

## Core Query Patterns

### User Activity History

```graphql
query TokenTransfers($owner: String!, $limit: Int!) {
  token_activities_v2(
    where: { owner_address: { _eq: $owner } },
    limit: $limit,
    order_by: { transaction_version: desc }
  ) {
    transaction_version
    event_account_address
    token_standard
    from_address
    to_address
    token_data_id
    amount
    type
    transaction_timestamp
    token_data {
      token_name
      collection_id
      current_collection {
        collection_name
        creator_address
      }
    }
  }
}
```

### Collection Activity Feed

```graphql
query CollectionActivities($collection_id: String!, $limit: Int!) {
  token_activities_v2(
    where: {
      token_data: {
        collection_id: { _eq: $collection_id }
      }
    },
    order_by: { transaction_version: desc },
    limit: $limit
  ) {
    type
    from_address
    to_address
    token_data_id
    transaction_timestamp
    transaction_version
  }
}
```

### Recent Mints

```graphql
query RecentMints($collection_id: String!) {
  token_activities_v2(
    where: {
      type: { _eq: "0x4::token::MintEvent" },
      token_data: {
        collection_id: { _eq: $collection_id }
      }
    },
    order_by: { transaction_version: desc },
    limit: 50
  ) {
    to_address
    token_data_id
    transaction_timestamp
    transaction_version
  }
}
```

### Sales and Transfers

```graphql
query TokenSales($token_data_id: String!) {
  token_activities_v2(
    where: {
      token_data_id: { _eq: $token_data_id },
      type: { _in: ["0x4::token::TransferEvent", "marketplace_sale"] }
    },
    order_by: { transaction_version: desc }
  ) {
    type
    from_address
    to_address
    transaction_version
    transaction_timestamp
    event_account_address
  }
}
```

### Burn Events

```graphql
query BurnedTokens($collection_id: String!) {
  token_activities_v2(
    where: {
      type: { _eq: "0x4::token::BurnEvent" },
      token_data: {
        collection_id: { _eq: $collection_id }
      }
    },
    order_by: { transaction_version: desc }
  ) {
    token_data_id
    from_address
    transaction_timestamp
  }
}
```

## Real-World Use Cases

1. **NFT Marketplaces**: Display comprehensive activity feeds showing mints, listings, sales, and transfers for collections and individual NFTs with real-time updates.

2. **Portfolio Trackers**: Show users their complete NFT transaction history including acquisitions, sales, transfers, and current holdings across all collections.

3. **Collection Analytics**: Analyze trading volumes, mint rates, holder behavior, and price trends for NFT collections to provide market intelligence.

4. **Provenance Tracking**: Build complete ownership histories showing every transfer from mint to current owner for authenticity verification.

5. **Notification Systems**: Alert users instantly when their NFTs are transferred, listed, sold, or when new items mint in collections they follow.

6. **Marketplace Aggregators**: Combine activity data from multiple marketplaces to provide comprehensive views of NFT trading across the ecosystem.

## Best Practices

**Filter by Activity Type**: Use the type field to distinguish between mints, transfers, burns, and marketplace events for appropriate handling.

**Paginate Results**: Implement cursor-based pagination for activity feeds to efficiently handle collections with high volumes of transactions.

**Join with Token Data**: Always join activities with token\_data to fetch metadata (names, images, attributes) for display.

**Cache Collection Metadata**: Collection-level data changes rarely - cache it aggressively to reduce duplicate queries.

**Handle Missing Data**: Not all activities have complete metadata - implement fallbacks for missing names, images, or attributes.

**Time-Based Filtering**: Use transaction\_timestamp for date range queries when analyzing historical trends or generating reports.

**Aggregate for Statistics**: Use aggregate queries to compute volumes, counts, and other metrics rather than client-side processing.

## TypeScript Integration

```typescript
import { ApolloClient, gql } from "@apollo/client";

const client = new ApolloClient({
  uri: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql"
});

interface TokenActivity {
  type: string;
  fromAddress: string;
  toAddress: string;
  tokenDataId: string;
  timestamp: string;
  tokenName: string;
  collectionName: string;
}

async function getActivityFeed(address: string, limit: number = 50): Promise<TokenActivity[]> {
  const { data } = await client.query({
    query: gql`
      query ActivityFeed($address: String!, $limit: Int!) {
        token_activities_v2(
          where: {
            _or: [
              { from_address: { _eq: $address } },
              { to_address: { _eq: $address } }
            ]
          },
          order_by: { transaction_version: desc },
          limit: $limit
        ) {
          type
          from_address
          to_address
          token_data_id
          transaction_timestamp
          token_data {
            token_name
            current_collection {
              collection_name
            }
          }
        }
      }
    `,
    variables: { address, limit }
  });

  return data.token_activities_v2.map((activity: any) => ({
    type: activity.type,
    fromAddress: activity.from_address,
    toAddress: activity.to_address,
    tokenDataId: activity.token_data_id,
    timestamp: activity.transaction_timestamp,
    tokenName: activity.token_data?.token_name || "Unknown",
    collectionName: activity.token_data?.current_collection?.collection_name || "Unknown"
  }));
}

// Format activity for display
function formatActivity(activity: TokenActivity): string {
  if (activity.type.includes("Mint")) {
    return `Minted ${activity.tokenName}`;
  } else if (activity.type.includes("Transfer")) {
    return `Transferred ${activity.tokenName} from ${activity.fromAddress.substring(0, 6)}... to ${activity.toAddress.substring(0, 6)}...`;
  } else if (activity.type.includes("Burn")) {
    return `Burned ${activity.tokenName}`;
  }
  return `${activity.type} - ${activity.tokenName}`;
}
```

## Advanced Queries

### Collection Trading Volume

```graphql
query TradingVolume($collection_id: String!, $since: timestamp!) {
  token_activities_v2_aggregate(
    where: {
      token_data: {
        collection_id: { _eq: $collection_id }
      },
      type: { _in: ["marketplace_sale", "0x4::token::TransferEvent"] },
      transaction_timestamp: { _gte: $since }
    }
  ) {
    aggregate {
      count
    }
  }

  activities: token_activities_v2(
    where: {
      token_data: {
        collection_id: { _eq: $collection_id }
      },
      type: { _in: ["marketplace_sale"] },
      transaction_timestamp: { _gte: $since }
    },
    order_by: { transaction_timestamp: desc }
  ) {
    transaction_timestamp
    from_address
    to_address
    token_data_id
  }
}
```

### Most Active Traders

```graphql
query ActiveTraders($collection_id: String!, $days: Int!) {
  token_activities_v2(
    where: {
      token_data: {
        collection_id: { _eq: $collection_id }
      },
      transaction_timestamp: { _gte: "now() - ${days} days" }
    },
    distinct_on: from_address
  ) {
    from_address
  }
}
```

### Token Provenance Chain

```graphql
query TokenHistory($token_data_id: String!) {
  token_activities_v2(
    where: { token_data_id: { _eq: $token_data_id } },
    order_by: { transaction_version: asc }
  ) {
    type
    from_address
    to_address
    transaction_version
    transaction_timestamp
    event_account_address
  }
}
```

## Activity Type Classification

Common activity types and their meanings:

- `0x4::token::MintEvent`: NFT was minted
- `0x4::token::TransferEvent`: NFT was transferred
- `0x4::token::BurnEvent`: NFT was burned/destroyed
- `marketplace_listing`: NFT was listed for sale
- `marketplace_sale`: NFT was sold
- `marketplace_delist`: Listing was cancelled

## Pagination Pattern

```typescript
async function getPaginatedActivities(
  address: string,
  limit: number,
  offset: number
): Promise<TokenActivity[]> {
  const { data } = await client.query({
    query: gql`
      query PaginatedActivities($address: String!, $limit: Int!, $offset: Int!) {
        token_activities_v2(
          where: { owner_address: { _eq: $address } },
          order_by: { transaction_version: desc },
          limit: $limit,
          offset: $offset
        ) {
          # fields...
        }
      }
    `,
    variables: { address, limit, offset }
  });

  return data.token_activities_v2;
}
```

## Related Concepts

- [Fungible Assets](https://www.dwellir.com/docs/aptos/fungible_assets) - Token balance queries
- [Aggregations](https://www.dwellir.com/docs/aptos/aggregations) - Activity statistics
- [Subscriptions](https://www.dwellir.com/docs/aptos/subscriptions) - Real-time activity streams
- [Object Model](https://www.dwellir.com/docs/aptos/object_model) - NFT architecture

---

## transactions_batch

# transactions_batch

## Overview

Submit multiple signed transactions in a single API call for improved throughput and reduced latency. Batch submission is ideal for applications that need to submit many transactions quickly, such as airdrops, batch payments, or high-frequency trading operations.

## Endpoint

`POST /v1/transactions/batch`

## Request

\###Request Body
Array of signed transaction objects:

```json
[
  {
    "sender": "0x...",
    "sequence_number": "1",
    "max_gas_amount": "2000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1234567890",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::aptos_account::transfer",
      "type_arguments": ["0x1::aptos_coin::AptosCoin"],
      "arguments": ["0x2", "1000"]
    },
    "signature": {...}
  }
]
```

## Response

### Success Response (202)

Returns array of transaction hashes or failure details:

```json
{
  "transaction_failures": []
}
```

Individual transactions may fail while others succeed. Check response details for each transaction status.

### Error Responses

| Status | Error Code          | Description                            |
| ------ | ------------------- | -------------------------------------- |
| 400    | invalid\_input      | Malformed batch or transaction objects |
| 413    | payload\_too\_large | Batch exceeds size limits              |

## Code Examples

```bash
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/batch" \
  -H "Content-Type: application/json" \
  -d '[{"sender":"0x...","payload":{"type":"entry_function_payload","function":"0x1::aptos_account::transfer","type_arguments":["0x1::aptos_coin::AptosCoin"],"arguments":["0x2","1000"]}}]'
```

Python batch submission:

```python
transactions = [build_transaction(recipient) for recipient in recipients]
response = client.submit_batch_transactions(transactions)
```

## Use Cases

Batch submission provides significant advantages for several scenarios:

1. **Airdrops**: Distribute tokens to hundreds or thousands of addresses efficiently by batching transfer transactions.

2. **Payroll Systems**: Process employee payments or rewards in bulk with a single API interaction.

3. **DEX Operations**: Submit multiple swap or liquidity provision transactions together for atomic execution or improved throughput.

4. **NFT Minting**: Batch mint operations for collections, reducing API overhead and improving deployment speed.

5. **Gaming Rewards**: Distribute in-game rewards or achievements to multiple players efficiently.

6. **Multi-Account Operations**: Execute operations across multiple accounts you control with coordinated submission.

## Best Practices

**Batch Size**: Keep batches under 100 transactions for optimal performance and reliability. Larger batches risk timeouts or partial failures.

**Sequence Number Management**: Ensure sequence numbers are correct and contiguous for transactions from the same sender. Gaps or duplicates cause failures.

**Gas Settings**: Set realistic gas limits for each transaction. One under-gased transaction doesn't affect others.

**Error Handling**: Implement retry logic for failed transactions within a batch. Successful transactions won't be resubmitted.

**Atomicity**: Batch submission doesn't guarantee atomic execution. Transactions execute independently and some may fail while others succeed.

**Rate Limits**: Batching counts toward API rate limits based on total transaction count, not API calls.

## Performance Considerations

Batch submission reduces HTTP overhead from N requests to 1 request for N transactions. This provides 5-10x throughput improvement for large batches compared to individual submission.

Processing time scales with batch size: 100 transactions typically process in 200-500ms total versus 10-30 seconds for individual submissions.

However, batched transactions still enter the mempool individually and execute in separate blocks based on gas price and network conditions.

---

## transactions_by_hash

# transactions_by_hash

## Overview

Retrieve a transaction by its unique hash. This is the primary method for looking up transactions when users provide transaction IDs, typically after submission or from block explorers. The response includes full execution results, events emitted, and gas consumption details.

## Endpoint

`GET /v1/transactions/by_hash/{txn_hash}`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_hash/0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383" \
      -H "Accept: application/json"
```

## Response Fields

- `version` (`string, required`): Ledger version where the transaction was committed
- `hash` (`string, required`): Transaction hash (matches the request parameter)
- `success` (`boolean, required`): Whether the Move VM executed the transaction successfully
- `vm_status` (`string, required`): Execution result detail or error message
- `gas_used` (`string, required`): Actual gas units consumed
- `sender` (`string, required`): Account that submitted and signed the transaction
- `sequence_number` (`string, required`): Sender's sequence number at submission time
- `payload` (`object, required`): The transaction payload (function call details)
- `events` (`array, required`): Events emitted during execution
- `timestamp` (`string, required`): Block timestamp in microseconds since Unix epoch
- `state_change_hash` (`string, required`): Hash of the state changes produced by this transaction
- `event_root_hash` (`string, required`): Merkle root of emitted events

## Successful Response

```json
{
  "version": "123456789",
  "hash": "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383",
  "state_change_hash": "0x...",
  "event_root_hash": "0x...",
  "state_checkpoint_hash": "0x...",
  "gas_used": "8",
  "success": true,
  "vm_status": "Executed successfully",
  "accumulator_root_hash": "0x...",
  "sender": "0xabc...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::aptos_account::transfer",
    "type_arguments": [],
    "arguments": ["0x2", "1000000"]
  },
  "signature": {
    "type": "ed25519_signature",
    "public_key": "0x...",
    "signature": "0x..."
  },
  "events": [
    {
      "guid": { "creation_number": "3", "account_address": "0xabc..." },
      "sequence_number": "15",
      "type": "0x1::coin::WithdrawEvent",
      "data": { "amount": "1000000" }
    }
  ],
  "timestamp": "1700000000000000"
}
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid hash format (must be 0x + 64 hex characters)

### Error 2

- Code: `transaction_not_found`
- Description: Transaction hash is unknown to the node and not present in the current mempool view

## Code Examples

cURL
Python
TypeScript
Rust

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_hash/0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

txn = client.transaction_by_hash(
    "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383"
)

print(f"Success: {txn['success']}")
print(f"Gas used: {txn['gas_used']}")
print(f"VM status: {txn['vm_status']}")
print(f"Version: {txn['version']}")

# Parse events
for event in txn.get("events", []):
    print(f"  Event: {event['type']} - {event['data']}")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

const txn = await aptos.getTransactionByHash({
  transactionHash: "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383"
});
console.log(`Status: ${txn.vm_status}`);
console.log(`Success: ${txn.success}`);
console.log(`Gas used: ${txn.gas_used}`);
console.log(`Events: ${txn.events?.length}`);
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let txn = client.get_transaction_by_hash(
    "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383".parse()?
).await?;

println!("Success: {}, Gas: {}", txn.inner().success, txn.inner().gas_used);
```

## Use Cases

1. **Transaction Confirmation**: After submitting a transaction, poll by hash to check execution status and confirm success or failure before updating application state.

2. **Receipt Generation**: Retrieve full transaction details including events, gas usage, and state changes to generate user-facing receipts and confirmation screens.

3. **Block Explorer Links**: Enable users to click transaction hashes in your UI and view complete transaction details, including payload, events, and gas consumption.

4. **Debugging Failed Transactions**: When transactions fail, retrieve the full transaction object to inspect `vm_status` and understand why execution failed (insufficient balance, abort codes, out of gas, etc.).

5. **Event Processing**: Extract emitted events from specific transactions to update application state, trigger notifications, or maintain off-chain indexes.

6. **Audit Logging**: Store transaction hashes in your database, then retrieve full details on-demand for audit trails without storing complete transaction data locally.

## Understanding vm\_status

The `vm_status` field contains the execution result. Common values:

| vm\_status                                                | Meaning                                      |
| --------------------------------------------------------- | -------------------------------------------- |
| `Executed successfully`                                   | Transaction completed without errors         |
| `Move abort in 0x1::coin: EINSUFFICIENT_BALANCE(0x10006)` | Move abort with error code                   |
| `Out of gas`                                              | Transaction ran out of gas before completing |
| `SEQUENCE_NUMBER_TOO_OLD`                                 | Sequence number was already used             |
| `TRANSACTION_EXPIRED`                                     | Transaction expired before execution         |

When `success` is `false`, the `vm_status` provides the specific error. Move abort codes are module-specific -- check the module's source code to decode the error constant name.

## Best Practices

**Hash Format**: Transaction hashes must be 0x-prefixed 64-character hex strings (32 bytes). Validate format before querying to avoid 400 errors.

**Pending Transactions**: Newly submitted transactions can return `200` with `type: "pending_transaction"` while they are still in the mempool. Use `wait_by_hash` or poll this endpoint until the response changes to a committed transaction payload.

**Caching**: Transaction data is immutable once committed. Cache successfully retrieved transactions indefinitely to minimize API calls. Only pending transactions (404 responses) need re-fetching.

**Sequence vs Hash**: If you know the transaction version (from block data or event streams), use `/transactions/by_version` for faster lookups. Hash lookups use a secondary index and are slightly slower.

**Error Interpretation**: Always check both `success` and `vm_status` fields. A transaction can be committed (not 404) but fail at the application level (`success: false`). Failed transactions still consume gas.

**Event Parsing**: Events in the response follow the same structure as the events endpoints. Use the `type` field to filter for events relevant to your application.

## Performance Considerations

Hash lookups use indexed storage and typically complete in 50-100ms. This is slightly slower than version-based lookups because hash indexes are secondary indexes in the transaction database.

Transaction objects can be large (10KB-1MB) depending on payload size, number of events, and state changes. Complex smart contract interactions with many events generate the largest responses.

For bulk transaction retrieval, use version-based queries or the transaction list endpoint with pagination instead of individual hash lookups, as they provide better database locality and throughput.

## Related Endpoints

- `/v1/transactions/by_version/{version}` - Faster lookup when version is known
- `/v1/transactions/wait_by_hash/{hash}` - Block until transaction is confirmed
- `/v1/transactions` - Submit a new transaction
- `/v1/transactions/simulate` - Test a transaction before submitting
- `/v1/accounts/{address}/transactions` - List all transactions for an account

---

## transactions_by_version

# transactions_by_version

## Overview

Retrieve a transaction by its ledger version number. This is the fastest transaction query method because versions are the primary index for transaction storage. Versions are assigned sequentially to every transaction on the blockchain, providing a total ordering of all state changes in Aptos.

## Endpoint

`GET /v1/transactions/by_version/{txn_version}`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_version/123456789" \
      -H "Accept: application/json"
```

## Response Fields

- `version` (`string, required`): Ledger version (matches the request parameter)
- `hash` (`string, required`): Unique transaction hash
- `success` (`boolean, required`): Whether the Move VM executed successfully
- `vm_status` (`string, required`): Execution result or error details
- `gas_used` (`string, required`): Actual gas units consumed
- `sender` (`string, required`): Account that submitted the transaction
- `sequence_number` (`string, required`): Sender's sequence number at submission
- `payload` (`object, required`): Transaction payload (function call, script, etc.)
- `events` (`array, required`): Events emitted during execution
- `timestamp` (`string, required`): Block timestamp in microseconds since Unix epoch
- `state_change_hash` (`string, required`): Hash of state changes produced
- `accumulator_root_hash` (`string, required`): Root hash of the transaction accumulator

## Successful Response

```json
{
  "version": "123456789",
  "hash": "0x0985b017...",
  "state_change_hash": "0x...",
  "event_root_hash": "0x...",
  "state_checkpoint_hash": "0x...",
  "gas_used": "8",
  "success": true,
  "vm_status": "Executed successfully",
  "accumulator_root_hash": "0x...",
  "sender": "0xabc...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::aptos_account::transfer",
    "type_arguments": [],
    "arguments": ["0x2", "1000000"]
  },
  "signature": {
    "type": "ed25519_signature",
    "public_key": "0x...",
    "signature": "0x..."
  },
  "events": [
    {
      "guid": { "creation_number": "3", "account_address": "0xabc..." },
      "sequence_number": "15",
      "type": "0x1::coin::WithdrawEvent",
      "data": { "amount": "1000000" }
    }
  ],
  "timestamp": "1700000000000000"
}
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid version format (must be a non-negative integer)

### Error 2

- Code: `transaction_not_found`
- Description: Version does not exist yet or has been pruned (before `oldest_ledger_version`)

## Code Examples

cURL
Python
TypeScript
Rust

```bash
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_version/123456789" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Fetch a single transaction by version
txn = client.transaction_by_version(123456789)
print(f"Hash: {txn['hash']}")
print(f"Sender: {txn['sender']}")
print(f"Success: {txn['success']}")
print(f"Gas used: {txn['gas_used']}")

# Process events from the transaction
for event in txn.get("events", []):
    print(f"  Event: {event['type']} - {event['data']}")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

const txn = await aptos.getTransactionByVersion({
  ledgerVersion: 123456789n
});
console.log(`Hash: ${txn.hash}`);
console.log(`Gas used: ${txn.gas_used}`);
console.log(`Events: ${txn.events?.length}`);
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let txn = client.get_transaction_by_version(123456789).await?;
println!("Hash: {}", txn.inner().hash);
println!("Success: {}", txn.inner().success);
```

## Version Number Properties

Transaction versions have important properties that make them ideal for indexing and state management:

| Property                 | Description                                                                 |
| ------------------------ | --------------------------------------------------------------------------- |
| Globally unique          | Each version appears exactly once across the entire blockchain              |
| Monotonically increasing | Versions always increase; there are no decreases or resets                  |
| No gaps                  | Every integer from 0 to the current version has a corresponding transaction |
| Sequential within blocks | Each block contains a contiguous range of versions                          |
| Starts at 0              | The genesis transaction has version 0                                       |
| Deterministic ordering   | Versions define the canonical order of all state changes                    |

These properties make versions ideal for checkpointing, streaming, and state machine replication. You can always resume processing from any version without missing transactions.

## Use Cases

1. **Sequential Processing**: Iterate through all transactions by incrementing version numbers, ensuring complete coverage with no missed transactions. This is the foundation of most indexing pipelines.

2. **Block Transaction Retrieval**: After getting a block with its version range (`first_version` to `last_version`), fetch individual transactions within that range for detailed processing.

3. **Event Source Lookup**: When an event references a version number, use this endpoint to retrieve the full transaction that emitted the event, including payload, sender, and other events.

4. **Historical Analysis**: Access transactions at specific points in blockchain history using version numbers as stable, permanent references.

5. **State Reconstruction**: Replay transactions in version order to reconstruct the state of any account or module at any historical point.

6. **Checkpoint Recovery**: After a processing interruption, resume from the last processed version number without risk of duplicate or missed transactions.

## Best Practices

**Version Range Awareness**: Check `GET /v1` (ledger info) to get `oldest_ledger_version` and `ledger_version` before querying. Versions outside this range return 404 errors.

**Version vs Hash**: Use version queries when you have version numbers (from blocks, events, or sequential processing). Use hash queries when users provide transaction IDs. Version queries are approximately 30-50% faster.

**Sequential Access Patterns**: When processing many sequential transactions, version-based queries provide significantly better database locality than hash-based queries, resulting in faster response times.

**Bulk Processing**: For processing large version ranges, use the `GET /v1/transactions?start={version}&limit=100` pagination endpoint instead of individual version queries. Fetching 100 transactions in one call is faster than 100 individual requests.

**Immutability and Caching**: Transaction data at a specific version never changes. Cache historical transactions (older than the latest few hundred versions) indefinitely to minimize API load. Only very recent versions might be affected by reorgs (extremely rare on Aptos).

**404 Disambiguation**: A 404 can mean the version is too new (not yet processed) or too old (pruned). Compare the requested version against `oldest_ledger_version` and `ledger_version` from ledger info to determine the cause.

**System Transaction Handling**: Some versions correspond to system transactions (block\_metadata, state\_checkpoint) rather than user transactions. These have no `sender` or `signature` fields. Handle both types in your processing logic.

## Performance Considerations

Version-based lookups are the fastest transaction query method, typically completing in 30-80ms. They use the primary index on transaction storage, providing optimal I/O patterns and minimal database overhead.

Response sizes match other transaction queries (2KB-1MB depending on complexity). The reduced query latency compared to hash lookups makes version-based access the preferred method for high-throughput indexing pipelines.

For sequential processing of large version ranges, the transaction streaming API (gRPC) provides substantially better throughput than individual REST queries. However, for spot-checking specific versions or low-volume access, the REST endpoint is simpler to integrate.

Performance comparison of query methods:

| Method           | Typical Latency        | Index Type      |
| ---------------- | ---------------------- | --------------- |
| By version       | 30-80ms                | Primary index   |
| By hash          | 50-100ms               | Secondary index |
| List (paginated) | 100-200ms per 100 txns | Sequential scan |

## Related Endpoints

- `/v1/transactions/by_hash/{hash}` - Look up by hash when version is not known
- `/v1/transactions` - List transactions with pagination for bulk retrieval
- `/v1/blocks/by_version/{version}` - Get the block containing this version
- `/v1/blocks/by_height/{height}` - Get block by height (includes version range)
- `/v1` - Get current and oldest available versions

---

## transactions_encode

# transactions_encode

## Overview

Encode a transaction into BCS (Binary Canonical Serialization) bytes ready for signing. This endpoint is the bridge between transaction construction and offline signing workflows. It takes a complete transaction object (without signature) and returns the canonical byte representation that must be signed to produce a valid signed transaction.

## Endpoint

`POST /v1/transactions/encode_submission`

## Request Parameters

- `sender` (`string, required`): Request Body: 0x-prefixed account address of the signer
- `sequence_number` (`string, required`): Request Body: Next sequence number for the sender account
- `max_gas_amount` (`string, required`): Request Body: Maximum gas units the sender is willing to pay
- `gas_unit_price` (`string, required`): Request Body: Price per gas unit in octas
- `expiration_timestamp_secs` (`string, required`): Request Body: Unix timestamp after which the transaction expires
- `payload` (`object, required`): Request Body: Transaction payload (entry_function_payload, script_payload, etc.)

## Request Example

```json
{
  "sender": "0x1a2b3c...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000120",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::aptos_account::transfer",
    "arguments": ["0x2a3b4c...", "1000000"]
  }
}
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (200) Returns the BCS-encoded transaction bytes as a hex string: ```json "0xb5e97db07fa0bd0e5598aa3643a9bc6f6693bddc1a9fec9e674a461eaa00b193..." ``` These bytes represent the signing message. Sign them with the sender's private key to produce a valid signature. ### Error Responses | Status | Error Code | Description | | -- | -- | -- | | 400 | invalid_input | Invalid transaction format or missing required fields | | 400 | invalid_payload | Payload doesn't conform to entry function or script requirements | | 400 | function_not_found | The specified Move function does not exist on-chain | | 400 | type_error | Type arguments don't match the function signature |

## Successful Response

```json
"0xb5e97db07fa0bd0e5598aa3643a9bc6f6693bddc1a9fec9e674a461eaa00b193..."
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid transaction format or missing required fields

### Error 2

- Code: `invalid_payload`
- Description: Payload doesn't conform to entry function or script requirements

### Error 3

- Code: `function_not_found`
- Description: The specified Move function does not exist on-chain

### Error 4

- Code: `type_error`
- Description: Type arguments don't match the function signature

## Code Examples

cURL
Python
TypeScript
Rust

```bash
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/encode_submission" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": "0x1a2b3c...",
    "sequence_number": "42",
    "max_gas_amount": "2000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000120",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::aptos_account::transfer",
      "arguments": ["0x2a3b4c...", "1000000"]
    }
  }'
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
account = Account.load_key("your_private_key_hex")

# Step 1: Build transaction object
raw_txn = {
    "sender": str(account.address()),
    "sequence_number": str(client.account_sequence_number(account.address())),
    "max_gas_amount": "2000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": str(int(time.time()) + 120),
    "payload": {
        "type": "entry_function_payload",
        "function": "0x1::aptos_account::transfer",
        "arguments": ["0x2a3b4c...", "1000000"]
    }
}

# Step 2: Encode for signing
encoded = client.encode_submission(raw_txn)

# Step 3: Sign the encoded bytes
to_sign = bytes.fromhex(encoded[2:])  # Remove 0x prefix
signature = account.sign(to_sign)

# Step 4: Submit with signature
raw_txn["signature"] = {
    "type": "ed25519_signature",
    "public_key": str(account.public_key()),
    "signature": str(signature)
}
result = client.submit_transaction(raw_txn)
```

```typescript
import { Aptos, AptosConfig, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// The TypeScript SDK handles encoding internally
// For manual encoding via REST:
const response = await fetch(
  "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/encode_submission",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      sender: "0x1a2b3c...",
      sequence_number: "42",
      max_gas_amount: "2000",
      gas_unit_price: "100",
      expiration_timestamp_secs: String(Math.floor(Date.now() / 1000) + 120),
      payload: {
        type: "entry_function_payload",
        function: "0x1::aptos_account::transfer",
        arguments: ["0x2a3b4c...", "1000000"]
      }
    })
  }
);
const encodedHex = await response.json();
// Sign encodedHex with your signing mechanism
```

```rust
use aptos_sdk::rest_client::Client;
use serde_json::json;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let txn = json!({
    "sender": "0x1a2b3c...",
    "sequence_number": "42",
    "max_gas_amount": "2000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000120",
    "payload": {
        "type": "entry_function_payload",
        "function": "0x1::aptos_account::transfer",
        "arguments": ["0x2a3b4c...", "1000000"]
    }
});

let encoded = client.encode_submission(&txn).await?;
// Sign the encoded bytes with your key management system
```

## Encoding Workflow

The complete encode-sign-submit workflow:

```
1. GET /v1/accounts/{address}          → sequence_number
2. GET /v1/estimate_gas_price          → gas_unit_price
3. Build transaction JSON              → raw transaction object
4. POST /v1/transactions/encode_submission → BCS-encoded bytes
5. Sign encoded bytes (offline)        → signature
6. POST /v1/transactions               → submit signed transaction
7. GET /v1/transactions/by_hash/{hash} → confirm execution
```

This separation enables secure signing workflows where the signing key never touches a networked machine.

## Use Cases

1. **Offline Signing**: Encode transactions on an online machine, transfer encoded bytes to an air-gapped signing device, then return signatures for submission. This is the gold standard for securing high-value operations.

2. **Hardware Wallet Integration**: Send encoded transaction bytes to hardware wallets (Ledger, Trezor) for signing, maintaining security while using blockchain APIs for transaction construction.

3. **Multi-Step Approval Workflows**: Separate transaction construction, review, approval, and signing into distinct steps for organizational governance. Each step can be handled by different systems or personnel.

4. **Cross-Platform Signing**: Encode on a server (web API) and sign on a different platform (mobile app, desktop wallet) without requiring the full Aptos SDK on both sides.

5. **Transaction Inspection**: Encode transactions to verify their exact on-chain representation before signing. Compare encoded bytes against expected values for audit and verification.

6. **Custodial Architectures**: In custodial wallet systems, the hot system builds and encodes transactions while the cold signing system only handles encoded bytes and produces signatures.

## Best Practices

**Complete Transaction Fields**: Include all required fields: sender, sequence\_number, max\_gas\_amount, gas\_unit\_price, expiration\_timestamp\_secs, and payload. Missing fields cause encoding failures.

**Sequence Number Management**: Fetch the latest sequence number from `GET /v1/accounts/{address}` immediately before encoding to avoid conflicts with concurrent transactions.

**Expiration Timestamps**: Set `expiration_timestamp_secs` to current time + 60-120 seconds. Factor in the time needed for the signing round trip when using offline signing -- add extra time for hardware wallet interactions.

**Chain ID Verification**: The encoding implicitly uses the node's chain ID. Ensure you are encoding against the correct network (mainnet vs testnet) to prevent cross-network issues.

**Byte Handling**: The returned hex string is 0x-prefixed. Remove the `0x` prefix before converting to byte arrays for signing. Most signing libraries expect raw bytes, not hex strings.

**Encoding Validation**: After encoding, optionally decode the bytes client-side to verify correctness before sending to signing devices. This catches errors before they reach expensive hardware signing steps.

## Security Considerations

Encoding itself does not involve cryptographic keys or sensitive data. However, the encoded bytes represent a transaction ready for signing -- treat them as sensitive in the following ways:

- **Verify before signing**: Always display or log the human-readable transaction details alongside encoded bytes so signers can verify what they are approving.
- **Secure transport**: When transmitting encoded bytes to signing devices, use authenticated channels to prevent man-in-the-middle modification.
- **Tamper detection**: Any modification to the encoded bytes produces a different signature that will be rejected by the network, providing built-in tamper evidence.

## Performance Considerations

Encoding is a fast, computational operation that validates the transaction against on-chain state (verifying the function exists, types match, etc.) but does not execute it. Response times are typically 20-50ms, dominated by network latency rather than encoding overhead.

Encoded transaction sizes vary:

- Simple transfers: 100-200 bytes
- Smart contract calls: 300-1,000 bytes
- Complex multi-agent transactions: 1-5KB

These sizes are negligible for modern networks but matter for hardware wallet display limitations and QR code encoding use cases.

## Related Endpoints

- `/v1/transactions` - Submit the signed transaction
- `/v1/transactions/simulate` - Simulate before encoding and signing
- `/v1/accounts/{address}` - Get current sequence number
- `/v1/estimate_gas_price` - Get gas price for transaction building
- `/v1/transactions/by_hash/{hash}` - Check submitted transaction status

---

## transactions_list

# transactions_list

## Overview

List transactions from the Aptos blockchain ordered by ledger version. Supports cursor-based pagination via the `start` parameter, making it suitable for sequential processing, indexing pipelines, and building block explorers. Returns transactions across all accounts, not filtered by sender.

## Endpoint

`GET /v1/transactions`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Get the 25 most recent transactions
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions?limit=25" \
      -H "Accept: application/json"

    # Get transactions starting from a specific version
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions?start=100000000&limit=100" \
      -H "Accept: application/json"
```

## Response Fields

- `version` (`string, required`): Unique, sequential ledger version number
- `hash` (`string, required`): Transaction hash
- `success` (`boolean, required`): Whether execution succeeded
- `vm_status` (`string, required`): Execution result or error message
- `gas_used` (`string, required`): Actual gas consumed
- `sender` (`string, required`): Account that submitted the transaction
- `payload` (`object, required`): The transaction payload
- `events` (`array, required`): Events emitted during execution
- `timestamp` (`string, required`): Block timestamp in microseconds

## Successful Response

```json
[
  {
    "version": "123456789",
    "hash": "0x0985b017...",
    "state_change_hash": "0x...",
    "event_root_hash": "0x...",
    "gas_used": "8",
    "success": true,
    "vm_status": "Executed successfully",
    "accumulator_root_hash": "0x...",
    "sender": "0xabc...",
    "sequence_number": "42",
    "max_gas_amount": "2000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000000",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::aptos_account::transfer",
      "type_arguments": [],
      "arguments": ["0x2", "1000000"]
    },
    "events": [...],
    "timestamp": "1700000000000000"
  }
]
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid start version or limit value

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Get the 25 most recent transactions
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions?limit=25" \
  -H "Accept: application/json"

# Get transactions starting from a specific version
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions?start=100000000&limit=100" \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Get recent transactions
txns = client.transactions(start=None, limit=25)
for txn in txns:
    print(f"v{txn['version']}: {txn.get('sender', 'system')} - {txn['vm_status']}")

# Paginate through all transactions from a checkpoint
def stream_transactions(client, start_version, batch_size=100):
    version = start_version
    while True:
        batch = client.transactions(start=version, limit=batch_size)
        if not batch:
            break  # Reached chain head
        for txn in batch:
            yield txn
        version = int(batch[-1]["version"]) + 1

for txn in stream_transactions(client, 100_000_000):
    process_transaction(txn)
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Get recent transactions
const txns = await aptos.getTransactions({
  options: { offset: 0, limit: 25 }
});
console.log(`Fetched ${txns.length} transactions`);

// Paginate starting from a specific version
const startVersion = 100_000_000n;
const batch = await aptos.getTransactions({
  options: { offset: Number(startVersion), limit: 100 }
});
for (const txn of batch) {
  console.log(`v${txn.version}: ${txn.success ? "OK" : "FAIL"}`);
}
```

```rust
use aptos_sdk::rest_client::Client;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

// Fetch a batch of transactions
let txns = client.get_transactions(Some(100_000_000), Some(100)).await?;
for txn in txns.inner() {
    println!("Version {}: {}", txn.version, txn.vm_status);
}
```

## Pagination Guide

This endpoint uses version-based cursor pagination:

1. **First page**: Omit `start` to get the most recent transactions, or specify a version to start from a specific point.
2. **Next page**: Take the `version` of the last transaction in the response, add 1, and use it as `start`.
3. **End detection**: An empty array or fewer results than `limit` means you have reached the current chain head.

```python
# Complete pagination pattern
start_version = 0
while True:
    txns = client.transactions(start=start_version, limit=100)
    if not txns:
        # Reached chain head - wait and retry for real-time tailing
        time.sleep(5)
        continue
    for txn in txns:
        process(txn)
    start_version = int(txns[-1]["version"]) + 1
```

Transactions are contiguous with no version gaps. If you encounter missing versions, it indicates a processing error that needs investigation.

## Use Cases

1. **Blockchain Explorers**: Display recent transactions on the homepage or activity feed, showing the latest network activity with filtering and search.

2. **Indexing Pipelines**: Sequentially process all transactions from a starting point to build custom indexes, analytics databases, or application-specific data stores.

3. **Activity Monitoring**: Poll recent transactions to monitor network activity, detect specific transaction patterns (large transfers, contract deployments), or trigger alerts.

4. **Historical Analysis**: Retrieve historical transaction ranges for data analysis, research, or regulatory compliance requirements.

5. **State Reconstruction**: Replay transactions in order to reconstruct account or contract state at any point in history.

6. **Testing and Debugging**: Fetch recent transactions to understand current network behavior during development and troubleshooting.

## Best Practices

**Optimal Limit Values**: Use `limit=100` for efficient bulk retrieval. Smaller limits require more API calls; larger values hit the 100-transaction maximum.

**Pagination Pattern**: Always use the last transaction's `version + 1` as the next `start` parameter. Never rely on `limit * page` calculations, as system transactions and version numbers are sequential.

**Rate Limiting**: When processing historical data, implement rate limiting (10-20 requests per second) to avoid overwhelming the API and hitting quota limits.

**Cursor Persistence**: Save your current position (start version) frequently. If processing stops, resume from the last successfully processed version rather than restarting from the beginning.

**Empty Response Handling**: An empty array means you have reached the current chain head. Wait 4-5 seconds (one block time) before polling again.

**System Transactions**: The response includes system transactions (block\_metadata, state\_checkpoint) alongside user transactions. Filter by `type` if you only need user transactions.

## Performance Considerations

Transaction list queries are optimized for sequential access patterns. Fetching 100 transactions typically completes in 100-200ms. Response times scale linearly with the limit value.

Total response size depends on transaction complexity:

- Simple transfers: approximately 2KB per transaction
- Smart contract calls: approximately 5-15KB per transaction
- Complex multi-agent transactions: approximately 20-50KB per transaction

For high-throughput processing, consider using the Aptos gRPC streaming API which provides 10-100x better throughput than REST pagination for sequential access to large ranges of transactions.

The default `limit` when not specified is 25 transactions. Always specify explicit limits for production code to ensure consistent behavior across API versions.

## Comparison with Streaming API

For processing large ranges of transactions:

| Feature                | REST Pagination              | gRPC Streaming                     |
| ---------------------- | ---------------------------- | ---------------------------------- |
| Integration complexity | Simple HTTP client           | gRPC client required               |
| Throughput             | 100-500 txns/sec             | 10,000-50,000 txns/sec             |
| Latency                | Per-request round trip       | Continuous stream                  |
| Best for               | Ad-hoc queries, small ranges | Real-time tailing, bulk historical |
| Protocol               | HTTP/JSON                    | gRPC/protobuf                      |

Choose REST for ad-hoc queries and small ranges. Choose gRPC streaming for real-time tailing or bulk historical processing.

## Related Endpoints

- `/v1/transactions/by_hash/{hash}` - Look up a specific transaction by hash
- `/v1/transactions/by_version/{version}` - Look up by version (faster for known versions)
- `/v1/accounts/{address}/transactions` - List transactions for a specific account
- `/v1` - Get current ledger version to determine the latest available data

---

## transactions_simulate

# transactions_simulate

## Overview

Simulate transaction execution without committing changes to the blockchain. This endpoint executes transactions in a sandboxed environment, returning gas costs, execution results, and potential errors without consuming gas or affecting on-chain state.

## Endpoint

`POST /v1/transactions/simulate`

## Request

### Request Body

Submit a transaction object similar to `/transactions` submission, but signatures can be omitted or set to zero-filled placeholders:

```json
{
  "sender": "0x...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1234567890",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::aptos_account::transfer",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0x2", "1000"]
  }
}
```

## Response

### Success Response (200)

Returns simulation results showing what would happen if the transaction were executed:

```json
{
  "version": "123456789",
  "hash": "0x...",
  "state_change_hash": "0x...",
  "event_root_hash": "0x...",
  "gas_used": "8",
  "success": true,
  "vm_status": "Executed successfully",
  "changes": [...],
  "events": [...],
  "timestamp": "1234567890"
}
```

When `success: false`, inspect `vm_status` for the failure reason.

### Error Responses

| Status | Error Code         | Description                          |
| ------ | ------------------ | ------------------------------------ |
| 400    | invalid\_input     | Malformed transaction or payload     |
| 400    | simulation\_failed | Transaction failed during simulation |

## Code Examples

```bash
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/simulate" \
  -H "Content-Type: application/json" \
  -d '{"sender":"0x...","payload":{"type":"entry_function_payload","function":"0x1::aptos_account::transfer","type_arguments":["0x1::aptos_coin::AptosCoin"],"arguments":["0x2","1000"]}}'
```

Python gas estimation:

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
txn = {...}  # Transaction object
simulation = client.simulate_transaction(txn, sender_account)
print(f"Estimated gas: {simulation[0]['gas_used']}")
print(f"Will succeed: {simulation[0]['success']}")
```

TypeScript example:

```typescript
const simulation = await aptos.transaction.simulate.simple({
  signerPublicKey: account.publicKey,
  transaction: rawTxn
});
console.log(`Gas estimate: ${simulation[0].gas_used}`);
```

## Use Cases

Transaction simulation is critical for building robust applications:

1. **Gas Estimation**: Accurately estimate gas costs before submission to set appropriate `max_gas_amount` and avoid under-provisioning that causes transaction failures.

2. **Pre-Flight Validation**: Verify transactions will succeed before asking users to sign, improving UX by catching errors early and preventing failed transaction costs.

3. **Complex Transaction Testing**: Test multi-step or conditional logic in smart contracts to ensure correct behavior before committing real transactions.

4. **Fee Display**: Show users estimated transaction fees before confirmation, enabling informed consent about transaction costs.

5. **Dry Runs**: Test transaction sequences (batch operations, DEX swaps, liquidations) to verify expected outcomes before execution.

6. **Error Debugging**: When developing smart contracts, simulate transactions to understand why they fail without spending gas on failed attempts.

## Best Practices

**Realistic Parameters**: Use realistic `max_gas_amount` and `gas_unit_price` values for accurate simulation. The VM may behave differently with unrealistic limits.

**Current State**: Simulations execute against current blockchain state. For time-sensitive operations, simulate immediately before submission as state can change rapidly.

**Sequence Numbers**: Use the account's next sequence number from `/v1/accounts/{address}`. Incorrect sequence numbers cause simulation failures.

**Signature Requirements**: Most simulations don't require valid signatures. Use zero-filled signature placeholders to avoid signing overhead.

**Multiple Simulations**: Simulate variants (different gas limits, argument values) to understand transaction behavior under various conditions.

**Expiration Handling**: Set expiration\_timestamp\_secs to a future time that matches intended submission time for accurate replay protection simulation.

**State Changes Inspection**: Examine the `changes` array to understand what state modifications will occur, useful for verifying contract correctness.

## Performance Considerations

Simulations execute the full transaction logic including Move VM execution, making them comparable in cost to actual execution. Response times typically range from 50-500ms depending on transaction complexity.

Simple transfers simulate in 50-100ms, while complex smart contract interactions can take 200-500ms. Simulations are slightly faster than real execution because they skip consensus and signature verification.

For batch gas estimation, simulate transactions in parallel using concurrent API requests rather than sequential simulation to minimize latency.

## Simulation vs Actual Execution

Key differences between simulation and real execution:

- No gas charges apply to simulations
- State changes are rolled back after simulation
- Simulations use current state, execution uses state at ledger version
- Failed simulations don't increment account sequence numbers
- Simulation results show hypothetical state changes that won't persist

Use simulation for cost estimation and validation, but be aware that state changes between simulation and execution can cause different outcomes for state-dependent logic.

---

## transactions_submit

# transactions_submit

## Overview

Submit a signed transaction to the Aptos blockchain for execution. This is the primary endpoint for writing on-chain state, executing Move entry functions, deploying modules, and transferring assets. The transaction must be properly constructed, signed, and BCS-encoded before submission.

## Endpoint

`POST /v1/transactions`

## Request Parameters

- `sender` (`string, required`): Request Body (JSON format): 0x-prefixed account address of the signer
- `sequence_number` (`string, required`): Request Body (JSON format): Next sequence number for the sender account
- `max_gas_amount` (`string, required`): Request Body (JSON format): Maximum gas units the sender is willing to pay
- `gas_unit_price` (`string, required`): Request Body (JSON format): Price per gas unit in octas (1 APT = 100,000,000 octas)
- `expiration_timestamp_secs` (`string, required`): Request Body (JSON format): Unix timestamp after which the transaction expires
- `payload` (`object, required`): Request Body (JSON format): Transaction payload describing the operation
- `signature` (`object, required`): Request Body (JSON format): Cryptographic signature over the transaction

## Request Example

```json
{
  "sender": "0x1a2b3c...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000120",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::aptos_account::transfer",
    "type_arguments": [],
    "arguments": ["0x2a3b4c...", "1000000"]
  },
  "signature": {
    "type": "ed25519_signature",
    "public_key": "0x...",
    "signature": "0x..."
  }
}
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (202) Returns a pending transaction object. The `202 Accepted` status indicates the transaction entered the mempool but has not yet been executed: ```json { "hash": "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383", "sender": "0x1a2b3c...", "sequence_number": "42", "max_gas_amount": "2000", "gas_unit_price": "100", "expiration_timestamp_secs": "1700000120", "payload": { "type": "entry_function_payload", "function": "0x1::aptos_account::transfer", "type_arguments": [], "arguments": ["0x2a3b4c...", "1000000"] } } ``` Use `GET /v1/transactions/wait_by_hash/{hash}` or poll `GET /v1/transactions/by_hash/{hash}` to wait for execution. ### Error Responses | Status | Error Code | Description | | -- | -- | -- | | 400 | invalid_input | Malformed transaction, missing fields, or invalid types | | 400 | invalid_signature | Signature verification failed | | 400 | sequence_number_too_old | Sequence number already used (transaction was already submitted) | | 400 | sequence_number_too_new | Sequence number is ahead of the account's current sequence | | 400 | transaction_expired | expiration_timestamp_secs is in the past | | 400 | insufficient_balance | Account cannot cover max_gas_amount * gas_unit_price | | 413 | payload_too_large | Transaction exceeds maximum allowed size | | 429 | too_many_requests | Rate limited; retry after a short delay | | 500 | internal_error | Server-side processing error |

## Successful Response

```json
{
  "hash": "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383",
  "sender": "0x1a2b3c...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000120",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::aptos_account::transfer",
    "type_arguments": [],
    "arguments": ["0x2a3b4c...", "1000000"]
  }
}
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Malformed transaction, missing fields, or invalid types

### Error 2

- Code: `invalid_signature`
- Description: Signature verification failed

### Error 3

- Code: `sequence_number_too_old`
- Description: Sequence number already used (transaction was already submitted)

### Error 4

- Code: `sequence_number_too_new`
- Description: Sequence number is ahead of the account's current sequence

### Error 5

- Code: `transaction_expired`
- Description: expiration_timestamp_secs is in the past

### Error 6

- Code: `insufficient_balance`
- Description: Account cannot cover max_gas_amount * gas_unit_price

### Error 7

- Code: `payload_too_large`
- Description: Transaction exceeds maximum allowed size

### Error 8

- Code: `too_many_requests`
- Description: Rate limited; retry after a short delay

### Error 9

- Code: `internal_error`
- Description: Server-side processing error

## Transaction Signing Flow

The complete submit workflow requires multiple steps:

1. **Get account info** -- fetch the current `sequence_number` from `GET /v1/accounts/{address}`
2. **Estimate gas** -- call `GET /v1/estimate_gas_price` for current gas pricing
3. **Build the transaction** -- construct the payload with all required fields
4. **Encode for signing** -- use `POST /v1/transactions/encode_submission` or client-side BCS encoding
5. **Sign** -- sign the encoded bytes with the sender's private key (Ed25519 or MultiEd25519)
6. **Submit** -- send the signed transaction to `POST /v1/transactions`
7. **Confirm** -- poll `GET /v1/transactions/by_hash/{hash}` until committed

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Submit a pre-signed JSON transaction
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": "0x1a2b3c...",
    "sequence_number": "42",
    "max_gas_amount": "2000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000120",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::aptos_account::transfer",
      "type_arguments": [],
      "arguments": ["0x2a3b4c...", "1000000"]
    },
    "signature": {
      "type": "ed25519_signature",
      "public_key": "0x...",
      "signature": "0x..."
    }
  }'
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import TransactionPayload, EntryFunction
from aptos_sdk.type_tag import TypeTag, StructTag

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
sender = Account.load_key("your_private_key_hex")

# Build and submit an APT transfer
payload = EntryFunction.natural(
    "0x1::aptos_account",
    "transfer",
    [],
    [
        TransactionArgument("0x2a3b4c...", Serializer.struct),
        TransactionArgument(1_000_000, Serializer.u64),
    ],
)

signed_txn = client.create_bcs_signed_transaction(sender, payload)
tx_hash = client.submit_bcs_transaction(signed_txn)
print(f"Submitted: {tx_hash}")

# Wait for confirmation
client.wait_for_transaction(tx_hash)
```

```typescript
import { Aptos, AptosConfig, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);
const sender = Account.fromPrivateKey({
  privateKey: new Ed25519PrivateKey("0x...")
});

// Build, sign, and submit an APT transfer
const txn = await aptos.transaction.build.simple({
  sender: sender.accountAddress,
  data: {
    function: "0x1::aptos_account::transfer",
    functionArguments: ["0x2a3b4c...", 1_000_000],
  },
});

const signedTxn = await aptos.transaction.sign({ signer: sender, transaction: txn });
const result = await aptos.transaction.submit.simple({ transaction: txn, senderAuthenticator: signedTxn });
console.log(`Submitted: ${result.hash}`);

// Wait for confirmation
const confirmed = await aptos.waitForTransaction({ transactionHash: result.hash });
console.log(`Success: ${confirmed.success}`);
```

```rust
use aptos_sdk::{
    rest_client::Client,
    types::LocalAccount,
    transaction_builder::TransactionFactory,
};

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let mut sender = LocalAccount::from_private_key("your_private_key", 0)?;

// Build and submit a transfer
let factory = TransactionFactory::new(chain_id);
let txn = factory
    .transfer(recipient_address, 1_000_000)
    .sender(sender.address())
    .sequence_number(sender.sequence_number())
    .build();

let signed = sender.sign_transaction(txn);
let pending = client.submit(&signed).await?;
let confirmed = client.wait_for_transaction(&pending).await?;
println!("Gas used: {}", confirmed.inner().gas_used);
```

## Use Cases

1. **Token Transfers**: Send APT between accounts using `0x1::aptos_account::transfer`, or use other entry functions when you need asset-specific transfer flows.

2. **Smart Contract Interaction**: Call any published Move entry function to interact with DeFi protocols, NFT marketplaces, or custom applications.

3. **Module Deployment**: Publish new Move modules to the blockchain using `module_bundle_payload`, enabling smart contract deployment and upgrades.

4. **Multi-Agent Transactions**: Execute transactions requiring multiple signers, such as atomic swaps or escrow operations.

5. **Governance Voting**: Submit votes on on-chain governance proposals through the appropriate governance module entry functions.

## Best Practices

**Sequence Number Management**: Fetch the latest sequence number immediately before building the transaction. For concurrent submissions from the same account, increment locally and handle `sequence_number_too_new` errors with retries.

**Gas Configuration**: Use `estimate_gas_price` for current pricing. Set `max_gas_amount` higher than expected consumption (simulate first) to avoid out-of-gas failures. Unused gas is not charged.

**Expiration Strategy**: Set `expiration_timestamp_secs` to current time + 60-120 seconds. Shorter expirations reduce the window for stale transactions; longer expirations risk mempool bloat.

**BCS vs JSON**: Use BCS encoding (`application/x.aptos.signed_transaction+bcs`) in production for smaller payloads and faster processing. JSON encoding is useful for debugging and development.

**Idempotency**: Resubmitting the same signed transaction is safe. The node deduplicates by hash in the mempool and rejects already-committed transactions with `sequence_number_too_old`.

**Error Recovery**: On `429` (rate limited), implement exponential backoff. On `sequence_number_too_old`, refresh the sequence number and rebuild. On `insufficient_balance`, check the account balance before retrying.

## Performance Considerations

Transaction submission typically completes in 50-200ms (time to enter the mempool). Actual execution occurs in the next 1-3 blocks (4-12 seconds on mainnet).

Transaction size affects submission time: simple transfers are under 500 bytes, while module deployments can reach the maximum transaction size. Larger payloads take longer to transmit and validate.

For high-throughput scenarios, pipeline submissions by incrementing sequence numbers locally rather than waiting for each transaction to confirm before sending the next.

## Related Endpoints

- `/v1/transactions/encode_submission` - Encode transaction for offline signing
- `/v1/transactions/simulate` - Simulate before submitting
- `/v1/transactions/by_hash/{hash}` - Check transaction status
- `/v1/transactions/wait_by_hash/{hash}` - Wait for confirmation
- `/v1/accounts/{address}` - Get current sequence number
- `/v1/estimate_gas_price` - Current gas pricing

---

## transactions_wait_by_hash

# transactions_wait_by_hash

## Overview

Wait for a transaction to be committed or to expire. This endpoint blocks (long-polls) until the transaction identified by its hash appears on-chain or the server-side wait window elapses. It is the recommended way to confirm transaction execution after submission.

> **Note:** Dwellir Aptos fullnodes do expose `/transactions/wait_by_hash`. Keep a polling fallback only when you need custom retry behavior in your own client.

If you call this endpoint with an unknown hash, the node may return `transaction_not_found` immediately instead of holding the request open for the full timeout window.

## Endpoint

`GET /v1/transactions/wait_by_hash/{txn_hash}`

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Native wait (when available)
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/wait_by_hash/0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383" \
      -H "Accept: application/json"

    # Polling fallback (recommended for shared nodes)
    curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_hash/0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383" \
      -H "Accept: application/json"
```

## Response Fields

- `version` (`string, required`): Ledger version where the transaction was committed
- `hash` (`string, required`): Transaction hash matching the request
- `success` (`boolean, required`): Whether the transaction executed successfully
- `vm_status` (`string, required`): Human-readable execution status or error message
- `gas_used` (`string, required`): Actual gas units consumed
- `events` (`array, required`): Events emitted during execution
- `timestamp` (`string, required`): Block timestamp in microseconds since Unix epoch

## Successful Response

```json
{
  "version": "123456789",
  "hash": "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383",
  "state_change_hash": "0x...",
  "event_root_hash": "0x...",
  "gas_used": "8",
  "success": true,
  "vm_status": "Executed successfully",
  "sender": "0xabc...",
  "sequence_number": "42",
  "max_gas_amount": "2000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": { "type": "entry_function_payload", "function": "0x1::aptos_account::transfer" },
  "events": [],
  "timestamp": "1700000000000000"
}
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Invalid hash format (must be 0x-prefixed, 64 hex chars)

### Error 2

- Code: `transaction_not_found`
- Description: Transaction hash is unknown to both committed storage and the current mempool view

## Polling Behavior

If you need custom timeout control or want to avoid a single long-held request, implement client-side polling:

1. Submit the transaction via `POST /v1/transactions`
2. Poll `GET /v1/transactions/by_hash/{hash}` at regular intervals
3. A `200` response with `type: "pending_transaction"` means the hash is known but not committed yet
4. A committed transaction also returns `200` -- check `type`, `success`, and `vm_status`
5. Stop polling when `expiration_timestamp_secs` has passed and the transaction has not appeared

Recommended polling interval is 1-2 seconds. Aptos block time is approximately 4 seconds on mainnet, so polling more frequently than once per second provides no benefit.

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Native wait (when available)
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/wait_by_hash/0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383" \
  -H "Accept: application/json"

# Polling fallback (recommended for shared nodes)
curl -X GET "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_hash/0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383" \
  -H "Accept: application/json"
```

```python
import time
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

def wait_for_transaction(txn_hash: str, timeout_secs: int = 30) -> dict:
    """Poll until a transaction is committed or the client-side timeout expires."""
    deadline = time.time() + timeout_secs
    while time.time() < deadline:
        try:
            txn = client.transaction_by_hash(txn_hash)
            if txn.get("type") == "pending_transaction":
                time.sleep(1.5)
                continue
            return txn
        except Exception:
            pass  # transaction not yet visible, retry
        time.sleep(1.5)
    raise TimeoutError(f"Transaction {txn_hash} not confirmed within {timeout_secs}s")

# Usage after submitting a transaction
result = wait_for_transaction("0x0985b017...")
print(f"Success: {result['success']}, Gas used: {result['gas_used']}")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// The SDK has built-in wait functionality
const txn = await aptos.waitForTransaction({
  transactionHash: "0x0985b017...",
  options: { timeoutSecs: 30, checkSuccess: true }
});
console.log(`Confirmed at version ${txn.version}`);

// Manual polling fallback
async function pollTransaction(hash: string, timeoutMs = 30000) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    try {
      const txn = await aptos.getTransactionByHash({ transactionHash: hash });
      if (txn.type !== "pending_transaction") return txn;
    } catch {
      // 404 - still pending
    }
    await new Promise(r => setTimeout(r, 1500));
  }
  throw new Error(`Timeout waiting for ${hash}`);
}
```

```rust
use aptos_sdk::rest_client::Client;
use std::time::{Duration, Instant};
use tokio::time::sleep;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);
let hash = "0x0985b0179db0c0971bb9bf331dff7fdae6dacf73cee48a1ec6be614f41d4d383";

// The Rust SDK provides wait_for_transaction
let txn = client.wait_for_transaction_by_hash(
    hash.parse()?,
    Duration::from_secs(30),
).await?;

println!("Success: {}, Version: {}", txn.inner().success, txn.inner().version);
```

## Use Cases

1. **Transaction Confirmation Flow**: After submitting a transfer or smart contract call, wait for on-chain confirmation before updating your application state or notifying the user.

2. **Sequential Transaction Pipelines**: When transactions depend on each other (such as approve then swap on a DEX), wait for each to confirm before submitting the next to ensure correct sequence numbers.

3. **Payment Processing**: In commerce applications, hold the checkout flow until the payment transaction is confirmed on-chain, then release the goods or services.

4. **Multi-Signature Coordination**: After the final signer submits a multi-sig transaction, all parties can wait on the hash to confirm the collective operation succeeded.

5. **Retry Logic**: If a transaction is not confirmed within the expected window, resubmit with a higher gas price or updated expiration to handle network congestion.

## Best Practices

**Client Timeouts**: If you wrap this endpoint with your own retry loop, set your HTTP timeout longer than the node's wait window and keep a separate client-side deadline for the overall confirmation flow.

**Expiration Awareness**: If `expiration_timestamp_secs` has passed and the transaction is not on-chain, it will never be executed. Stop polling and consider resubmitting.

**Success vs Execution**: A confirmed transaction (`200` response) does not guarantee success. Always check the `success` field -- a transaction can be committed but fail at the Move VM level (for example, insufficient balance).

**Idempotency**: Polling `by_hash` is safe to repeat. The same hash always returns the same committed transaction once available.

**Connection Timeouts**: When using the native blocking endpoint, ensure your HTTP client timeout comfortably exceeds the server's wait window so the request is not cut off prematurely.

## Performance Considerations

The native `wait_by_hash` endpoint uses server-side long polling, which is more efficient than client-side polling because it avoids repeated HTTP round trips. Use polling when you need custom retry control or want to multiplex many outstanding waits in your own worker.

With client-side polling at 1.5-second intervals, a typical transaction confirms after 2-3 polls (3-5 seconds). The overhead is minimal: each poll is a lightweight hash-indexed lookup completing in 50-100ms.

For applications processing many concurrent transactions, use parallel polling with a shared connection pool rather than sequential waits to maximize throughput.

## Related Endpoints

- `/v1/transactions` - Submit a signed transaction
- `/v1/transactions/by_hash/{txn_hash}` - Get transaction by hash (non-blocking)
- `/v1/transactions/by_version/{txn_version}` - Get transaction by version
- `/v1/transactions/simulate` - Simulate before submitting

---

## upgradability

# upgradability

Smart contract upgradability is a critical feature on Aptos that allows developers to fix bugs, add features, and improve performance while maintaining the same on-chain address. Move's upgrade system provides powerful flexibility with built-in safety checks to prevent breaking changes that could corrupt existing on-chain state or break dependent contracts.

## Overview

On Aptos, modules can be upgraded by publishing new versions to the same address. The blockchain enforces compatibility rules to ensure that upgrades don't break existing functionality or corrupt stored data. Upgrades can be configured with different policies ranging from fully immutable (no upgrades allowed) to arbitrary (any changes permitted), with compatibility checks as the recommended middle ground.

## Upgrade Policies

Aptos supports three upgrade policies that control what changes are permitted:

```move
// In Move.toml or via CLI
[package]
name = "MyProject"
version = "1.0.0"
upgrade_policy = "compatible"  // Options: immutable, compatible, arbitrary
```

**Immutable**: Once published, the module cannot be upgraded. This provides maximum security and predictability but eliminates flexibility to fix bugs or add features.

**Compatible** (Recommended): Upgrades must maintain backward compatibility. Public functions, struct layouts, and type signatures cannot change in breaking ways, but you can add new functions and internal improvements.

**Arbitrary**: Any changes are permitted including breaking changes to public APIs and struct layouts. Use with extreme caution as this can corrupt on-chain data.

## Compatibility Rules

When using the compatible upgrade policy, the following rules apply:

### Allowed Changes

- Adding new functions (public, entry, or internal)
- Adding new structs and types
- Adding new fields to structs (with care)
- Modifying internal function implementations
- Improving gas efficiency
- Adding new modules to the package

### Prohibited Changes

- Removing public functions
- Changing public function signatures (parameters or return types)
- Removing or reordering existing struct fields
- Changing struct abilities (key, store, copy, drop)
- Removing or renaming modules
- Changing friend declarations that break existing integrations

## Upgrade Process

```bash
# 1. Prepare the upgraded module
# Edit your Move code with compatible changes

# 2. Test the upgrade locally
aptos move test --package-dir .

# 3. Compile with upgrade check
aptos move compile --package-dir . --save-metadata

# 4. Deploy the upgrade
aptos move publish \
  --package-dir . \
  --named-addresses my_project=0xYOUR_ADDRESS \
  --profile mainnet

# 5. Verify the upgrade
aptos move view \
  --function-id 0xYOUR_ADDRESS::module::version \
  --profile mainnet
```

## Version Management

Implement version tracking in your modules:

```move
module 0x1::upgradeable_contract {
    use std::signer;

    const VERSION: u64 = 2; // Increment with each upgrade

    struct Config has key {
        version: u64,
        admin: address,
        // Other config fields
    }

    public entry fun initialize(account: &signer) {
        move_to(account, Config {
            version: VERSION,
            admin: signer::address_of(account)
        });
    }

    // Migration function for upgrades
    public entry fun migrate(admin: &signer) acquires Config {
        let config = borrow_global_mut<Config>(signer::address_of(admin));
        assert!(config.version < VERSION, 1); // Already migrated

        // Perform migration logic
        if (config.version == 1) {
            // Migrate from v1 to v2
            config.version = VERSION;
        };
    }

    #[view]
    public fun get_version(addr: address): u64 acquires Config {
        borrow_global<Config>(addr).version
    }
}
```

## Safe Struct Evolution

When adding fields to structs, ensure backward compatibility:

```move
// Version 1
struct UserProfile has key {
    name: vector<u8>,
    created_at: u64
}

// Version 2 - Safe addition with default handling
struct UserProfile has key {
    name: vector<u8>,
    created_at: u64,
    avatar_url: Option<vector<u8>>  // Use Option for new fields
}

// Migration helper
public fun migrate_profile(user: &signer) acquires UserProfile {
    let profile = borrow_global_mut<UserProfile>(signer::address_of(user));
    // Existing profiles automatically get None for new optional field
}
```

## Real-World Use Cases

1. **Bug Fixes**: Quickly patch security vulnerabilities or logical errors in deployed contracts without changing addresses or disrupting users.

2. **Feature Additions**: Add new functionality to existing protocols like new token types, additional governance mechanisms, or enhanced analytics.

3. **Performance Optimization**: Upgrade contract implementations to use more efficient algorithms or data structures while maintaining the same external interface.

4. **Parameter Tuning**: Adjust economic parameters, fee structures, or limits in DeFi protocols based on real-world usage and market conditions.

5. **Emergency Responses**: Implement circuit breakers, pause functionality, or other emergency measures when security issues are discovered.

6. **Protocol Evolution**: Gradually evolve complex protocols like DEXes or lending platforms by adding new features while maintaining backward compatibility with existing integrations.

## Best Practices

**Always Use Compatible Mode**: Unless you have specific requirements, use the compatible upgrade policy to balance flexibility with safety.

**Version All Modules**: Include version constants in all modules and expose them through view functions for transparency and debugging.

**Test Upgrades Thoroughly**: Test upgraded modules against existing on-chain state before deploying to mainnet. Use testnet to validate migration paths.

**Implement Migration Functions**: Provide explicit migration functions for users to upgrade their stored data when struct layouts change.

**Document Breaking Changes**: Even when using arbitrary mode, clearly document all changes and provide migration guides for users and integrators.

**Use Multi-Sig for Upgrades**: Require multiple signatures for upgrade transactions on production contracts to prevent unauthorized or accidental upgrades.

**Gradual Rollout**: For major upgrades, consider implementing feature flags that allow gradual activation after deployment.

**Preserve Historical Versions**: Keep records of all deployed versions with their code and deployment transactions for audit and recovery purposes.

## Package Manager Pattern

For complex upgrades, consider implementing a package manager:

```move
module 0x1::package_manager {
    struct PackageMetadata has key {
        name: vector<u8>,
        version: u64,
        upgrade_number: u64,
        upgrade_policy: u8,
        source_digest: vector<u8>
    }

    public entry fun record_upgrade(
        publisher: &signer,
        version: u64,
        digest: vector<u8>
    ) acquires PackageMetadata {
        let addr = signer::address_of(publisher);
        if (!exists<PackageMetadata>(addr)) {
            move_to(publisher, PackageMetadata {
                name: b"MyPackage",
                version,
                upgrade_number: 0,
                upgrade_policy: 1, // compatible
                source_digest: digest
            });
        } else {
            let metadata = borrow_global_mut<PackageMetadata>(addr);
            metadata.version = version;
            metadata.upgrade_number = metadata.upgrade_number + 1;
            metadata.source_digest = digest;
        };
    }
}
```

## Related Concepts

- [Module Structure](https://www.dwellir.com/docs/aptos/module_structure) - Design modules for upgradability
- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Handle resource migration
- [Testing](https://www.dwellir.com/docs/aptos/testing) - Test upgrade scenarios
- [Formal Verification](https://www.dwellir.com/docs/aptos/formal_verification) - Verify upgrade safety properties

---

## user_transactions

> Coming soon: Need support for this? Email <support@dwellir.com> and we will enable it for you.

# user_transactions

## Overview

Query transactions submitted by a specific address.

## Query Structure

```graphql
query GetUserTransactions($address: String!, $limit: Int) {
  user_transactions(
    where: { sender: { _eq: $address } }
    limit: $limit
    order_by: { version: desc }
  ) {
    version
    hash
    success
    vm_status
    gas_used
  }
}
```

## Variables

| Name    | Type   | Required | Description     |
| ------- | ------ | -------- | --------------- |
| address | String | Yes      | Account address |
| limit   | Int    | No       | Result limit    |

## Code Examples

Python
TypeScript

```
import requests
query = """query GetUserTransactions($address: String!, $limit: Int) { user_transactions(where: { sender: { _eq: $address } }, limit: $limit, order_by: { version: desc }) { version hash success vm_status gas_used } }"""
variables = {"address": "0x1", "limit": 10}
requests.post("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql", json={"query": query, "variables": variables})
```

```
const query = `query GetUserTransactions($address: String!, $limit: Int) { user_transactions(where: { sender: { _eq: $address } }, limit: $limit, order_by: { version: desc }) { version hash success vm_status gas_used } }`;
const variables = { address: "0x1", limit: 10 };
await fetch("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables }) });
```

---

## view

# view

## Overview

Execute a Move view function without submitting a transaction, consuming gas, or requiring a signature. View functions are read-only operations that run in the Move VM and return computed results. They are the most efficient way to query on-chain state that requires computation, such as calculated balances, prices, permissions, or derived values.

Only functions explicitly marked `view` can be called through this endpoint. The target function must actually be marked as view. A regular public function is not enough on its own.

## Endpoint

`POST /v1/view`

## Request Parameters

- `ledger_version` (`string, optional`): Query parameter: Execute the view function against state at this historical version
- `function` (`string, required`): Request Body: Fully qualified function identifier: `address::module::function_name`
- `type_arguments` (`array, required`): Request Body: Type parameters for generic functions (empty array if none needed)
- `arguments` (`array, required`): Request Body: Function arguments as JSON values (strings for addresses, numbers, booleans)

## Request Example

```json
{
  "function": "0x1::coin::balance",
  "type_arguments": ["0x1::aptos_coin::AptosCoin"],
  "arguments": ["0x1"]
}
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (200) Returns an array of return values from the function: ```json [ "1500000000" ] ``` Return values are JSON-encoded according to their Move types. Functions returning multiple values produce arrays with multiple elements. ### Error Responses | Status | Error Code | Description | | -- | -- | -- | | 400 | invalid_input | Malformed request body, unknown function, or wrong number of arguments | | 400 | function_not_found | The specified function does not exist at the given address | | 400 | type_error | Type arguments don't match function signature | | 500 | vm_error | Function execution failed in the Move VM (such as arithmetic overflow, abort) |

## Successful Response

```json
[
  "1500000000"
]
```

## Error Responses

### Error 1

- Code: `invalid_input`
- Description: Malformed request body, unknown function, or wrong number of arguments

### Error 2

- Code: `function_not_found`
- Description: The specified function does not exist at the given address

### Error 3

- Code: `type_error`
- Description: Type arguments don't match function signature

### Error 4

- Code: `vm_error`
- Description: Function execution failed in the Move VM (such as arithmetic overflow, abort)

## Code Examples

cURL
Python
TypeScript
Rust

```bash
# Check APT balance
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view" \
  -H "Content-Type: application/json" \
  -d '{"function":"0x1::coin::balance","type_arguments":["0x1::aptos_coin::AptosCoin"],"arguments":["0x1"]}'

# Check if an account is registered for a coin
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view" \
  -H "Content-Type: application/json" \
  -d '{"function":"0x1::coin::is_account_registered","type_arguments":["0x1::aptos_coin::AptosCoin"],"arguments":["0x1"]}'

# Query at a historical version
curl -s -X POST "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view?ledger_version=50000000" \
  -H "Content-Type: application/json" \
  -d '{"function":"0x1::coin::balance","type_arguments":["0x1::aptos_coin::AptosCoin"],"arguments":["0x1"]}'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Check APT balance
result = client.view_function(
    "0x1::coin::balance",
    ["0x1::aptos_coin::AptosCoin"],
    ["0x1"]
)
balance_octas = int(result[0])
print(f"Balance: {balance_octas / 1e8} APT")

# Check coin registration
registered = client.view_function(
    "0x1::coin::is_account_registered",
    ["0x1::aptos_coin::AptosCoin"],
    ["0x1"]
)
print(f"Registered: {registered[0]}")

# Query total supply
supply = client.view_function(
    "0x1::coin::supply",
    ["0x1::aptos_coin::AptosCoin"],
    []
)
print(f"Supply: {supply[0]}")
```

```typescript
import { Aptos, AptosConfig } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Check APT balance
const [balance] = await aptos.view({
  payload: {
    function: "0x1::coin::balance",
    typeArguments: ["0x1::aptos_coin::AptosCoin"],
    functionArguments: ["0x1"]
  }
});
console.log(`Balance: ${Number(balance) / 1e8} APT`);

// Check if account exists
const [exists] = await aptos.view({
  payload: {
    function: "0x1::account::exists_at",
    typeArguments: [],
    functionArguments: ["0x1"]
  }
});
console.log(`Account exists: ${exists}`);

// Query a custom DeFi protocol
const [price] = await aptos.view({
  payload: {
    function: "0xdex_address::pool::get_price",
    typeArguments: ["0x1::aptos_coin::AptosCoin", "0xusdc_address::usdc::USDC"],
    functionArguments: []
  }
});
```

```rust
use aptos_sdk::rest_client::Client;
use serde_json::json;

let client = Client::new("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1".parse()?);

let result = client.view(
    &json!({
        "function": "0x1::coin::balance",
        "type_arguments": ["0x1::aptos_coin::AptosCoin"],
        "arguments": ["0x1"]
    }),
    None,  // ledger_version
).await?;
println!("Balance: {:?}", result.inner());
```

## Common View Function Patterns

### Balance and Token Queries

```json
// Check coin balance
{ "function": "0x1::coin::balance", "type_arguments": ["0x1::aptos_coin::AptosCoin"], "arguments": ["0x1"] }

// Check if registered for a coin
{ "function": "0x1::coin::is_account_registered", "type_arguments": ["0x1::aptos_coin::AptosCoin"], "arguments": ["0x1"] }

// Get coin decimals
{ "function": "0x1::coin::decimals", "type_arguments": ["0x1::aptos_coin::AptosCoin"], "arguments": [] }

// Get coin name
{ "function": "0x1::coin::name", "type_arguments": ["0x1::aptos_coin::AptosCoin"], "arguments": [] }

// Get coin supply
{ "function": "0x1::coin::supply", "type_arguments": ["0x1::aptos_coin::AptosCoin"], "arguments": [] }
```

### Account and System Queries

```json
// Check if account exists
{ "function": "0x1::account::exists_at", "type_arguments": [], "arguments": ["0x1"] }

// Read a view that is explicitly marked `view`
{ "function": "0x1::account::exists_at", "type_arguments": [], "arguments": ["0x1"] }
```

## Use Cases

1. **Balance Queries**: Check account balances for any fungible token without transaction overhead or gas costs. Ideal for wallet UIs, portfolio trackers, and balance verification.

2. **State Inspection**: Read computed contract state like pool prices, lending rates, or staking rewards that require on-chain calculation rather than simple resource reads.

3. **Validation Checks**: Verify conditions before transaction submission (sufficient balance, correct permissions, valid parameters) to prevent failed transactions and wasted gas.

4. **UI Data Fetching**: Power application UIs with real-time blockchain data. View functions are fast enough for user-facing queries without needing a dedicated indexer.

5. **Price Feeds**: Query DEX pool prices, oracle data, or computed exchange rates for display, trading logic, or arbitrage detection.

6. **Permission Checks**: Verify user roles, capabilities, or access control before allowing operations in your application.

## Best Practices

**Function Visibility**: Only functions explicitly marked with the `#[view]` attribute can be called via this endpoint. Entry functions and ordinary `public fun` functions that are not declared as view functions cannot be used here, even if they only read state.

**Gas-Free Execution**: View functions do not consume gas or require signatures, making them ideal for frequent, high-volume queries from frontends and monitoring systems.

**Type Arguments**: Provide full type paths including generics. For example, use `0x1::aptos_coin::AptosCoin` rather than just `AptosCoin`. Type arguments correspond to the generic parameters in the function signature.

**Argument Encoding**: Arguments are passed as JSON values and automatically BCS-encoded by the API. Large integers (u64 and above) must be passed as strings to avoid JSON precision loss.

**Caching**: View function results reflect the state at the current (or specified) ledger version. Cache based on how frequently the underlying state changes -- token balances change with every transfer, while protocol parameters may change infrequently.

**Ledger Version**: Use the `ledger_version` query parameter to query historical state. This enables time-travel queries and consistent multi-call snapshots when all calls use the same version.

**Error Handling**: View functions that call `abort` in the Move VM return a 500 error. Check for this when querying functions that have assertion checks (such as querying a balance for a non-existent coin store).

## Performance Considerations

View functions execute directly in the Move VM without consensus or state commitment overhead. Response times are typically 20-100ms depending on function complexity.

- Simple reads (balance, existence check): 20-50ms
- Moderate computation (price calculation, aggregate queries): 50-100ms
- Complex computations (multi-step simulations): 100-200ms

View functions are significantly faster than full transaction simulation for read operations. For frequently accessed data, implement client-side caching with TTLs based on block time (approximately 4 seconds on mainnet).

For batch queries, make concurrent requests rather than sequential calls. View functions are stateless and can safely run in parallel without ordering concerns.

## Related Endpoints

- `/v1/accounts/{address}/resource/{resource_type}` - Direct resource read (no computation)
- `/v1/accounts/{address}/resources` - List all resources under an account
- `/v1/accounts/{address}/modules` - Discover available view functions via ABI
- `/v1/transactions/simulate` - Simulate a full transaction with state changes

---

## view_functions

# view_functions

View functions provide gas-free read access to on-chain state, enabling applications to query smart contract data without submitting transactions or paying fees. They are essential for building responsive user interfaces, analytics dashboards, and efficient off-chain systems that need to read blockchain state frequently.

## Overview

View functions in Aptos are special functions marked with the `#[view]` attribute that can be called through the REST API without creating a transaction. They are read-only, cannot modify state, and execute immediately without waiting for block confirmation. This makes them perfect for displaying balances, checking permissions, computing derived values, and providing real-time data to applications.

## Defining View Functions

View functions must be public and marked with the `#[view]` attribute:

```move
module 0x1::token_info {
    use std::signer;
    use std::string::String;

    struct TokenStore has key {
        balance: u64,
        name: String,
        symbol: String,
        decimals: u8
    }

    struct Supply has key {
        total: u64,
        max: u64
    }

    // Simple view function
    #[view]
    public fun balance_of(owner: address): u64 acquires TokenStore {
        if (!exists<TokenStore>(owner)) {
            return 0
        };
        borrow_global<TokenStore>(owner).balance
    }

    // View function with multiple parameters
    #[view]
    public fun allowance(owner: address, spender: address): u64 acquires Allowances {
        // Return approved amount for spender
        0
    }

    // View function returning multiple values
    #[view]
    public fun token_metadata(addr: address): (String, String, u8) acquires TokenStore {
        let store = borrow_global<TokenStore>(addr);
        (store.name, store.symbol, store.decimals)
    }

    // View function with computation
    #[view]
    public fun circulating_supply(): u64 acquires Supply {
        let supply = borrow_global<Supply>(@0x1);
        supply.total
    }

    // View function checking conditions
    #[view]
    public fun is_paused(): bool acquires Config {
        borrow_global<Config>(@0x1).paused
    }

    // View function with vector return
    #[view]
    public fun get_holders(start: u64, limit: u64): vector<address> acquires HolderRegistry {
        // Return list of token holders
        vector::empty()
    }
}
```

## Calling View Functions

### REST API

View functions are called via HTTP POST to the `/v1/view` endpoint:

```bash
curl -X POST https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view \
  -H "Content-Type: application/json" \
  -d '{
    "function": "0x1::token_info::balance_of",
    "type_arguments": [],
    "arguments": ["0x123abc..."]
  }'
```

Response:

```json
{
  "result": ["1000000"]
}
```

### TypeScript SDK

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.MAINNET,
  fullnode: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
});
const aptos = new Aptos(config);

// Call view function
const balance = await aptos.view({
  payload: {
    function: "0x1::token_info::balance_of",
    typeArguments: [],
    functionArguments: ["0x123abc..."]
  }
});

console.log(`Balance: ${balance[0]}`);

// Call view function with multiple returns
const [name, symbol, decimals] = await aptos.view({
  payload: {
    function: "0x1::token_info::token_metadata",
    typeArguments: [],
    functionArguments: ["0x1"]
  }
});
```

### Python SDK

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account_address import AccountAddress

client = RestClient("https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Call view function
balance = client.view_function(
    function="0x1::token_info::balance_of",
    type_arguments=[],
    arguments=["0x123abc..."]
)

print(f"Balance: {balance[0]}")
```

## Complex View Functions

### Aggregating Data

```move
#[view]
public fun get_portfolio_value(owner: address): u64 acquires TokenStore, PriceOracle {
    let total_value = 0u64;
    let store = borrow_global<TokenStore>(owner);
    let price = get_token_price(); // Internal helper

    total_value = store.balance * price / 1000000; // Adjust for decimals
    total_value
}

#[view]
public fun get_top_holders(limit: u64): vector<address> acquires HolderRegistry {
    // Query and sort holders by balance
    // Return top N addresses
    vector::empty()
}
```

### Pagination Support

```move
#[view]
public fun get_transactions(
    account: address,
    offset: u64,
    limit: u64
): vector<Transaction> acquires TransactionHistory {
    let history = borrow_global<TransactionHistory>(account);
    // Return paginated results
    vector::empty()
}
```

## Real-World Use Cases

1. **Wallet Displays**: Fetch token balances, NFT collections, and transaction history to display in user wallets without gas costs.

2. **DeFi Dashboards**: Query liquidity pool reserves, staking rewards, lending positions, and APY calculations for real-time financial data.

3. **NFT Marketplaces**: Check NFT ownership, metadata, listing prices, and royalty information to populate marketplace listings efficiently.

4. **Analytics Platforms**: Aggregate protocol metrics like total value locked, trading volumes, user counts, and historical statistics.

5. **Gaming Applications**: Retrieve player stats, inventory items, leaderboard positions, and game state without requiring transactions.

6. **Permission Checks**: Verify user access rights, admin privileges, or whitelist status before displaying UI elements or allowing actions.

## Best Practices

**Keep Computations Light**: View functions execute during API calls, so avoid expensive computations. Consider pre-computing values in transaction functions and storing them.

**Return Meaningful Defaults**: Use defensive programming to return sensible defaults (like 0 for balances) when resources don't exist, avoiding errors in calling code.

**Use Pagination**: For functions returning large datasets, implement offset and limit parameters to prevent timeouts and excessive response sizes.

**Cache Results**: On the application side, cache view function results when appropriate to reduce API calls and improve performance.

**Validate Inputs**: Check that addresses and parameters are valid to provide better error messages than internal assertion failures.

**Document Return Types**: Clearly document what each view function returns, especially when returning multiple values or complex structures.

**Consider Gas Limits**: While view functions don't charge gas, they still have execution limits. Very complex computations may timeout.

## View Functions vs Entry Functions

```move
// Entry function - Modifies state, requires transaction
public entry fun transfer(from: &signer, to: address, amount: u64) acquires TokenStore {
    // Mutates state
    let from_store = borrow_global_mut<TokenStore>(signer::address_of(from));
    from_store.balance = from_store.balance - amount;
    // ...
}

// View function - Read-only, no transaction needed
#[view]
public fun balance_of(owner: address): u64 acquires TokenStore {
    // Only reads state
    borrow_global<TokenStore>(owner).balance
}
```

## Error Handling

```move
#[view]
public fun safe_balance_of(owner: address): u64 acquires TokenStore {
    // Handle non-existent resources gracefully
    if (!exists<TokenStore>(owner)) {
        return 0
    };

    let store = borrow_global<TokenStore>(owner);
    store.balance
}

#[view]
public fun get_allowance_or_max(
    owner: address,
    spender: address
): u64 acquires Allowances {
    if (!exists<Allowances>(owner)) {
        return 0xFFFFFFFFFFFFFFFF // Return max u64 if no allowance set
    };
    // Return actual allowance
    0
}
```

## Performance Considerations

View functions execute on fullnodes during API requests, so optimize for speed:

- Minimize the number of `borrow_global` calls
- Avoid nested loops with large iterations
- Use early returns to skip unnecessary computation
- Pre-compute complex values in transaction functions when possible
- Consider implementing summary resources for expensive aggregations

## Related Concepts

- [Module Structure](https://www.dwellir.com/docs/aptos/module_structure) - Organize view functions effectively
- [Resource Management](https://www.dwellir.com/docs/aptos/resource_management) - Read resources safely
- [Testing](https://www.dwellir.com/docs/aptos/testing) - Test view function logic
- [GraphQL API](https://www.dwellir.com/docs/aptos/graphql/overview) - Alternative querying approach

---

## Arbitrum - Leading Ethereum L2 Scaling Solution

# Arbitrum - Leading Ethereum L2 Scaling Solution

## Arbitrum RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Arbitrum supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Arbitrum?

Arbitrum is the leading Ethereum Layer 2 scaling solution, processing more transactions than Ethereum mainnet itself. Built with Optimistic Rollup technology, Arbitrum offers:

### **Lightning Fast Performance**

- **Sub-second block times** - Ultra-fast L2 transaction confirmations
- **10-50x lower costs** than Ethereum mainnet
- **40,000 TPS capacity** - Massive throughput for any scale

### **Enterprise Security**

- **$15B+ secured** - Largest L2 by Total Value Locked
- **Ethereum security** - Full fraud proof protection
- **Battle-tested** - Processing 1M+ transactions daily since 2021

### **Massive Ecosystem**

- **3M+ unique addresses** - Largest L2 user base
- **600+ protocols** - Complete DeFi, Gaming, and NFT ecosystem
- **Native integrations** - GMX, Uniswap V3, Aave, Curve

## Quick Start with Arbitrum

Connect to Arbitrum One in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Arbitrum One mainnet
const provider = new JsonRpcProvider(
  'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Arbitrum One mainnet
const web3 = new Web3(
  'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Arbitrum:', chainId === 42161);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { arbitrum } from 'viem/chains';

// Create Arbitrum client
const client = createPublicClient({
  chain: arbitrum,
  transport: http('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 42161     | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | ETH       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Arbitrum supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods plus L2-specific optimizations.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // L2 specific: Check L1 data availability
  if (receipt.l1Fee) {
    console.log('L1 data cost:', receipt.l1Fee);
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Arbitrum One:

```javascript
// Estimate L2 execution gas
const l2Gas = await provider.estimateGas(tx);

// Get current L1 data fee (Arbitrum specific)
const l1DataFee = await provider.send('eth_estimateL1Fee', [tx]);

// Total cost = L2 execution + L1 data posting
const totalCost = l2Gas + BigInt(l1DataFee);
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Arbitrum recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class ArbitrumProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for L1 fee"

Arbitrum transactions require ETH for both L2 execution and L1 data availability:

```javascript
// Always account for L1 fees in balance checks
const balance = await provider.getBalance(address);
const l1Fee = await provider.send('eth_estimateL1Fee', [tx]);
const l2Gas = await provider.estimateGas(tx);
const totalRequired = l2Gas + BigInt(l1Fee) + tx.value;

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more ETH`);
}
```

### Error: "Transaction underpriced"

Arbitrum uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Arbitrum One requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

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

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (42161)
// Note: Separate block numbers
// Note: L1 data fees apply
```

## Resources & Tools

### Official Resources

- [Arbitrum Documentation](https://docs.arbitrum.io)
- [Arbitrum Bridge](https://bridge.arbitrum.io)
- [Arbitrum Block Explorer](https://arbiscan.io)

### Developer Tools

- [Hardhat Config](https://docs.arbitrum.io/for-devs/quickstart-solidity-hardhat)
- [Foundry Setup](https://docs.arbitrum.io/for-devs/quickstart-solidity-hardhat)
- [Development Frameworks](https://docs.arbitrum.io/build-decentralized-apps/reference/development-frameworks)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Arbitrum with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## arb_getL1ConfirmationNumber - Get L1 confir...

# arb_getL1ConfirmationNumber - Get L1 confir...

Get L1 confirmation number on the Arbitrum network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "arb_getL1ConfirmationNumber",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

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

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "arb_getL1ConfirmationNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'arb_getL1ConfirmationNumber',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## debug_traceBlock - Arbitrum RPC Method

# debug_traceBlock - Arbitrum RPC Method

Traces all transactions in a block on Arbitrum by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Arbitrum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Arbitrum
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Arbitrum:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Arbitrum blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arbitrum/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/arbitrum/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Arbitrum RPC Method

# debug_traceBlockByHash - Arbitrum RPC Method

Traces all transactions in a block on Arbitrum identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Arbitrum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Arbitrum
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Arbitrum:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Arbitrum:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/arbitrum/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arbitrum/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/arbitrum/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Arbitrum RPC Method

# debug_traceBlockByNumber - Arbitrum RPC Method

Traces all transactions in a block on Arbitrum identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Arbitrum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Arbitrum execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Arbitrum:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Arbitrum:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/arbitrum/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arbitrum/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/arbitrum/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Arbitrum RPC Method

# debug_traceCall - Arbitrum RPC Method

Traces a call on Arbitrum without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Arbitrum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Arbitrum
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "data": "0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
        "data": "0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
        "data": "0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    data: '0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    data: '0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    'data': '0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
        "data": "0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Arbitrum to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Arbitrum:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Arbitrum:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/arbitrum/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arbitrum/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Arbitrum RPC Method

# debug_traceTransaction - Arbitrum RPC Method

Traces a transaction execution on Arbitrum by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Arbitrum
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/arbitrum/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arbitrum/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Arbitrum RPC Method

# eth_accounts - Arbitrum RPC Method

Returns a list of addresses owned by the client on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

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

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/arbitrum/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Arbitrum RPC Method

# eth_blockNumber - Arbitrum RPC Method

Returns the number of the most recent block on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Syncing Applications** - Keep your dApp in sync with the latest Arbitrum blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Arbitrum block:', blockNumber);

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Arbitrum block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Arbitrum block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Arbitrum block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arbitrum block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Arbitrum:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Arbitrum:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Arbitrum node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/arbitrum/eth_syncing) - Check if node is still syncing

---

## eth_call - Arbitrum RPC Method

# eth_call - Arbitrum RPC Method

Executes a new message call immediately without creating a transaction on Arbitrum. Used for reading smart contract state.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Arbitrum
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';
const walletAddress = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Arbitrum. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Arbitrum
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Arbitrum

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "data": "0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "data": "0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    contractAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    data := common.FromHex("0x70a0823100000000000000000000000013867a801e352e219c2d2AC29288Bf086e5C81ef")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Arbitrum RPC Method

# eth_chainId - Arbitrum RPC Method

Returns the chain ID used for transaction signing on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/arbitrum/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/arbitrum/eth_syncing) - Check sync status

---

## eth_coinbase - Arbitrum RPC Method

# eth_coinbase - Arbitrum RPC Method

Checks the legacy `eth_coinbase` compatibility method on Arbitrum. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Arbitrum coinbase:', result);
}

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Arbitrum coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Arbitrum coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Arbitrum coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Arbitrum coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Arbitrum nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/arbitrum/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/arbitrum/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/arbitrum/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Arbitrum RPC Method

# eth_estimateGas - Arbitrum RPC Method

Estimates the gas necessary to execute a transaction on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Arbitrum
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x13867a801e352e219c2d2AC29288Bf086e5C81ef', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x13867a801e352e219c2d2AC29288Bf086e5C81ef', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Arbitrum.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

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

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Arbitrum may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "to": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x13867a801e352e219c2d2AC29288Bf086e5C81ef', 0.1)
```

```go
package main

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

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

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

    toAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/arbitrum/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 data postin...

# eth_estimateL1Fee - Estimate L1 data postin...

Estimate L1 data posting fee on the Arbitrum network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

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

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateL1Fee",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_estimateL1Fee',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_feeHistory - Arbitrum RPC Method

# eth_feeHistory - Arbitrum RPC Method

Returns historical gas fee data on Arbitrum, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Arbitrum without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Arbitrum.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Arbitrum) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

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

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

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

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/arbitrum/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/arbitrum/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Arbitrum RPC Method

# eth_gasPrice - Arbitrum RPC Method

Returns the current gas price on Arbitrum in wei.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Arbitrum
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Arbitrum. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Arbitrum, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Arbitrum: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Arbitrum supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

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

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

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

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/arbitrum/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/arbitrum/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Arbitrum RPC Method

# eth_getBalance - Arbitrum RPC Method

Returns the balance of a given address on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Arbitrum
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Arbitrum
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

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

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Arbitrum. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Arbitrum`);
  return balance;
}

displayBalance('0x13867a801e352e219c2d2AC29288Bf086e5C81ef');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Arbitrum at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Arbitrum')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Arbitrum')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Arbitrum.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/arbitrum/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Arbitrum RPC Method

# eth_getBlockByHash - Arbitrum RPC Method

Returns information about a block by hash on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Arbitrum
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Arbitrum.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Arbitrum.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const blockHash = '0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockHash := common.HexToHash("0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/arbitrum/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Arbitrum RPC Method

# eth_getBlockByNumber - Arbitrum RPC Method

Returns information about a block by block number on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Arbitrum
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Arbitrum with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Arbitrum. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

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

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

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

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/arbitrum/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Arbitrum RPC Method

# eth_getBlockReceipts - Arbitrum RPC Method

Returns all transaction receipts for a block on Arbitrum. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Arbitrum, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Arbitrum. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xcb51ef4d410f0ddfdf102f18e40a7e44748001bae0b0f5bc065aadd13fa3c9b0",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Arbitrum RPC Method

# eth_getCode - Arbitrum RPC Method

Returns the bytecode at a given address on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Arbitrum
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Arbitrum:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Arbitrum:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/arbitrum/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/arbitrum/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Arbitrum RPC Method

# eth_getFilterChanges - Arbitrum RPC Method

Polls a filter on Arbitrum for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Arbitrum
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

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

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

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

    // Create a log filter
    contractAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Arbitrum:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arbitrum/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/arbitrum/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/arbitrum/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arbitrum/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/arbitrum/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Arbitrum RPC Method

# eth_getFilterLogs - Arbitrum RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Arbitrum. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Arbitrum
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arbitrum/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arbitrum/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/arbitrum/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arbitrum/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Arbitrum RPC Method

# eth_getLogs - Arbitrum RPC Method

Returns an array of all logs matching a given filter object on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Arbitrum for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Arbitrum
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

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

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Arbitrum.

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

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Arbitrum enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Arbitrum, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arbitrum/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arbitrum/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Arbitrum RPC Method

# eth_getStorageAt - Arbitrum RPC Method

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

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **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 high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **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": [
    "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "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-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x13867a801e352e219c2d2AC29288Bf086e5C81ef', '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-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';

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-arbitrum-mainnet-archive.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 = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
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-arbitrum-mainnet-archive.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-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    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 Arbitrum:

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.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-arbitrum-mainnet-archive.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 = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef';
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 Arbitrum:`);
  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/arbitrum/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/arbitrum/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/arbitrum/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Arbitrum RPC Method

# eth_getTransactionByHash - Arbitrum RPC Method

Returns the information about a transaction by transaction hash on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Arbitrum
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Arbitrum. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Arbitrum. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const txHash = '0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Arbitrum RPC Method

# eth_getTransactionCount - Arbitrum RPC Method

Returns the number of transactions sent from an address on Arbitrum, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Arbitrum
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

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

## 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-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x13867a801e352e219c2d2AC29288Bf086e5C81ef', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Arbitrum nonce:', nonce);

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

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

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x13867a801e352e219c2d2AC29288Bf086e5C81ef'
nonce = get_transaction_count(address)
print(f'Arbitrum nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Arbitrum nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Arbitrum:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x13867a801e352e219c2d2AC29288Bf086e5C81ef');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/arbitrum/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Arbitrum RPC Method

# eth_getTransactionReceipt - Arbitrum RPC Method

Returns the receipt of a transaction by transaction hash on Arbitrum. Receipt is only available for mined transactions.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Arbitrum and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Arbitrum. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Arbitrum, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x6d26bc1cde1ce724eadaf4448431aa79a323ab58212c4ec39b5569b201ffaee2")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/arbitrum/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Arbitrum RPC Method

# eth_hashrate - Arbitrum RPC Method

Returns the legacy `eth_hashrate` compatibility value on Arbitrum. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Arbitrum hashrate:', parseInt(payload.result, 16), 'H/s');
}

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Arbitrum hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Arbitrum hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Arbitrum hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Arbitrum hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/arbitrum/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/arbitrum/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/arbitrum/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Arbitrum RPC Method

# eth_maxPriorityFeePerGas - Arbitrum RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Arbitrum. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Arbitrum
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Arbitrum priority fee:', priorityFeeGwei, 'Gwei');

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Arbitrum priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

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

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

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

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Arbitrum priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Arbitrum:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Arbitrum:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/arbitrum/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/arbitrum/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Arbitrum RPC Method

# eth_mining - Arbitrum RPC Method

Checks the legacy `eth_mining` compatibility method on Arbitrum. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Arbitrum mining:', payload.result);
}

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Arbitrum mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Arbitrum mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Arbitrum mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Arbitrum mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/arbitrum/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/arbitrum/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/arbitrum/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Arbitrum RPC Method

# eth_newBlockFilter - Arbitrum RPC Method

Creates a filter on Arbitrum that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Block Monitoring** - Detect new blocks on Arbitrum as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

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

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

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Arbitrum:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arbitrum/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arbitrum/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/arbitrum/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arbitrum/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Arbitrum RPC Method

# eth_newFilter - Arbitrum RPC Method

Creates a filter object on Arbitrum based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Event Monitoring** - Subscribe to specific contract events on Arbitrum such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x13867a801e352e219c2d2AC29288Bf086e5C81ef",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    contractAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Arbitrum:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x13867a801e352e219c2d2AC29288Bf086e5C81ef',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arbitrum/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/arbitrum/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/arbitrum/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arbitrum/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/arbitrum/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Arbitrum RPC Method

# eth_newPendingTransactionFilter - Arbitrum RPC Method

Creates a filter on Arbitrum that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Mempool Monitoring** - Observe unconfirmed transactions on Arbitrum to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for high-volume DeFi (GMX, Uniswap, Aave), gaming, and cross-chain applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Arbitrum...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Arbitrum:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arbitrum/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arbitrum/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Arbitrum RPC Method

# eth_protocolVersion - Arbitrum RPC Method

Returns the current Ethereum protocol version used by the Arbitrum node.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Arbitrum protocol version:', version);

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

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Arbitrum protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Arbitrum protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Arbitrum protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arbitrum protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Arbitrum nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/arbitrum/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/arbitrum/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/arbitrum/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Arbitrum RPC Method

# eth_sendRawTransaction - Arbitrum RPC Method

Submits a pre-signed transaction for broadcast to Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Arbitrum
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x13867a801e352e219c2d2AC29288Bf086e5C81ef', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Arbitrum mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/arbitrum/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x13867a801e352e219c2d2AC29288Bf086e5C81ef")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/arbitrum/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arbitrum/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Arbitrum RPC Method

# eth_sendTransaction - Arbitrum RPC Method

Creates and sends a new transaction from an unlocked account on Arbitrum. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Arbitrum tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Arbitrum tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Arbitrum tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Arbitrum tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arbitrum tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Arbitrum dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/arbitrum/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/arbitrum/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Arbitrum RPC Method

# eth_signTransaction - Arbitrum RPC Method

Signs a transaction with the private key of the specified account on Arbitrum without submitting it to the network.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Arbitrum tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Arbitrum tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Arbitrum tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Arbitrum:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/arbitrum/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/arbitrum/eth_accounts) - List accounts available for signing

---

## eth_syncing - Arbitrum RPC Method

# eth_syncing - Arbitrum RPC Method

Returns the sync status of your Arbitrum node - either `false` when fully synced, or an object describing the sync progress.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Arbitrum node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Arbitrum node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Arbitrum node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/arbitrum/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/arbitrum/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/arbitrum/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/arbitrum/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Arbitrum RPC Method

# eth_uninstallFilter - Arbitrum RPC Method

Removes a filter on Arbitrum that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arbitrum/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/arbitrum/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/arbitrum/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arbitrum/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/arbitrum/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Arbitrum RPC Method

# net_listening - Arbitrum RPC Method

Checks whether the connected Arbitrum client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`net_listening` is useful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

try {
  const listening = await provider.send('net_listening', []);
  console.log('Arbitrum node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Arbitrum node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Arbitrum node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/arbitrum/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/arbitrum/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/arbitrum/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/arbitrum/web3_clientVersion) - Get node client info

---

## net_peerCount - Arbitrum RPC Method

# net_peerCount - Arbitrum RPC Method

Returns the number of peers currently connected to your Arbitrum node.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`net_peerCount` is important for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Arbitrum deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Arbitrum peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Arbitrum peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Arbitrum peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Arbitrum nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/arbitrum/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/arbitrum/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/arbitrum/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/arbitrum/web3_clientVersion) - Get node client info

---

## net_version - Arbitrum RPC Method

# net_version - Arbitrum RPC Method

Returns the current network ID on Arbitrum as a decimal string. The network ID identifies which network the node is connected to.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`net_version` is essential for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Endpoint Identification** - Confirm your application is connected to the expected Arbitrum network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const networkId = await provider.send('net_version', []);
console.log('Arbitrum network ID:', networkId);

// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Arbitrum network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arbitrum network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/arbitrum/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/arbitrum/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/arbitrum/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/arbitrum/eth_syncing) - Check node sync progress

---

## rpc_modules - Arbitrum RPC Method

# rpc_modules - Arbitrum RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Arbitrum endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/arbitrum/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arbitrum/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Arbitrum RPC Method

# web3_clientVersion - Arbitrum RPC Method

Returns the current client software version string for your Arbitrum node, including the client name, version number, OS, and runtime.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Arbitrum client:', clientVersion);

// Using fetch
const response = await fetch('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Arbitrum client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arbitrum client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/arbitrum/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/arbitrum/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/arbitrum/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/arbitrum/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Arbitrum RPC Method

# web3_sha3 - Arbitrum RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Arbitrum.

> **Why Arbitrum?** Build on Ethereum's leading Layer 2 with 46% L2 market share and $12B+ TVL with full EVM compatibility, 1.5M daily transactions, and $3B+ DAO treasury for ecosystem growth.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, protocol teams, and dApp builders seeking Ethereum scalability:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

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

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

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

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

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-arbitrum-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/arbitrum/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/arbitrum/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/arbitrum/web3_clientVersion) - Get node client version

---

## Arc RPC Documentation

# Arc RPC Documentation

## Arc RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Arc supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Arc?

Arc is Circle's Layer 1 for programmable money. It is EVM compatible, so Solidity, Foundry, Hardhat, viem, and ethers all work unchanged. Two things make it behave differently from every other EVM chain you have integrated: **USDC is the native gas token**, and **blocks are final the moment they commit**.

### Stablecoin-Native Economics

- **USDC pays for gas** - No separate gas asset to acquire, hold, or top up. Users transact in the same unit they hold.
- **Predictable fees** - An EIP-1559 market with EWMA smoothing targets roughly $0.01 per transaction, so short demand spikes do not propagate into sudden fee jumps.
- **Dollar-denominated cost** - Fee estimates convert directly to dollars, which simplifies checkout, treasury, and reconciliation logic.

### Deterministic Finality

- **Sub-second settlement** - Malachite BFT consensus finalizes blocks in under a second on a Proof-of-Authority validator set.
- **No reorgs** - A transaction is either unconfirmed or final. One confirmation is enough; there is no confirmation-count threshold to tune and no rollback path to write.
- **\~0.5 second blocks** - Fast enough for point-of-sale flows and multi-step onchain workflows that would otherwise need polling between steps.

### Standard EVM Tooling

- **Osaka baseline** - Arc targets the Osaka hard fork, including EIP-7702 set-code transactions, and ships EIP-7708 ahead of upstream.
- **Reth execution** - The execution layer is Reth, so standard Ethereum tooling works unchanged. Dwellir's endpoint serves `eth_*`, `net_*`, `web3_*`, `debug_*`, and `trace_*`, plus Arc-specific reads such as `arc_getCertificate`.
- **HTTPS and WebSocket** - The same endpoint shape and authentication model as every other EVM network on Dwellir.

## Quick Start with Arc

Connect to Arc mainnet through Dwellir's HTTPS and WebSocket endpoints:

### Installation and Setup

Ethers.js
viem
Web3.py
WebSocket

```javascript
import { ethers } from 'ethers';

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

const network = await provider.getNetwork();
console.log(network.chainId === 5042n);

// Native balance is USDC with 18 decimals; divide by 1e12 to display as USDC
const balance = await provider.getBalance('0x3600000000000000000000000000000000000000');
console.log('USDC:', ethers.formatUnits(balance, 18));
```

```typescript
import { createPublicClient, defineChain, http } from 'viem';

const arc = defineChain({
  id: 5042,
  name: 'Arc',
  nativeCurrency: { name: 'USDC', symbol: 'USDC', decimals: 18 },
  rpcUrls: {
    default: {
      http: ['https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
});

const client = createPublicClient({
  chain: arc,
  transport: http(),
});

const blockNumber = await client.getBlockNumber();
```

```python
from web3 import Web3

web3 = Web3(Web3.HTTPProvider(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'
))

print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # 5042
print('Latest block:', web3.eth.block_number)
```

```javascript
import { ethers } from 'ethers';

const provider = new ethers.WebSocketProvider(
  'wss://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'
);

provider.on('block', (blockNumber) => {
  console.log('New Arc block:', blockNumber);
});
```

## Network Specifications

| Parameter        | Value                                       | Details                                                       |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------- |
| Chain ID         | 5042                                        | Mainnet, hexadecimal `0x13b2`                                 |
| Native currency  | USDC                                        | 18 decimals natively, 6 decimals through the ERC-20 interface |
| Consensus        | Malachite BFT                               | Tendermint-based, Proof-of-Authority validator set            |
| Execution        | Reth                                        | Rust Ethereum client with Arc-specific protocol modules       |
| EVM baseline     | Osaka                                       | Plus EIP-7708 from the upcoming Amsterdam fork                |
| Block time       | \~0.5 seconds                               | Sub-second block production                                   |
| Finality         | <1 second                                   | Deterministic; final on commit, no reorganizations            |
| Block gas limit  | 30,000,000                                  | \~60M gas per second at 0.5s blocks                           |
| Minimum base fee | 20 Gwei                                     | Protocol floor; lower-priced transactions are dropped         |
| RPC standard     | Ethereum                                    | JSON-RPC 2.0 over HTTPS and WSS                               |
| Explorer         | [explorer.arc.io](https://explorer.arc.io/) | Mainnet explorer                                              |

## API Reference

Arc supports the standard Ethereum JSON-RPC surface. Dwellir's endpoint also serves the `debug_*` and `trace_*` namespaces from archive nodes. The `txpool_*` namespace is not enabled; those calls return `-32601 Method not found`.

Mining methods are not documented for Arc. There is no proof-of-work and no miner: blocks are produced by a rotating proposer from the Proof-of-Authority validator set, so `eth_mining`, `eth_hashrate`, and `eth_coinbase` have no meaning on this network.

## RPC Capabilities

| Capability           | Support       | Operational note                                                                             |
| -------------------- | ------------- | -------------------------------------------------------------------------------------------- |
| HTTPS JSON-RPC       | Supported     | Reads, writes, historical queries, and tracing                                               |
| WebSocket JSON-RPC   | Supported     | Use for `eth_subscribe`, and for stateful filter workflows                                   |
| Historical state     | Archive       | Blocks, receipts, logs, and state back to genesis                                            |
| `debug_*` namespace  | Supported     | `debug_traceTransaction`, `debug_traceBlockByNumber`, `debug_traceCall`, and related tracers |
| `trace_*` namespace  | Supported     | Parity-style traces: `trace_transaction`, `trace_block`, `trace_filter`, and related methods |
| `txpool_*` namespace | Not enabled   | Returns `-32601 Method not found`                                                            |
| Blob transactions    | Not supported | Arc does not implement EIP-4844; type-3 transactions are rejected                            |
| Stateful filters     | Supported     | Filter IDs are backend-local and require connection affinity                                 |

## What Changes When USDC Is the Gas Token

These are the Arc behaviors most likely to break an integration ported from another EVM chain. Each one is also documented on the individual method pages.

### Two decimal precisions, one balance

USDC on Arc exposes the same balance through a native interface (18 decimals) and an ERC-20 interface (6 decimals) at `0x3600000000000000000000000000000000000000`. There is no wrapper token and these are not two assets.

```javascript
const native = await provider.getBalance(address);        // 18 decimals
const display = native / 10n ** 12n;                      // USDC, 6-decimal units
```

Credit and record balances from the 18-decimal value. The ERC-20 view truncates sub-USDC fractions, so crediting from `balanceOf` records less than was transferred, and a `balanceOf` of `0` does not prove the account is empty. Never mix `msg.value` with `USDC.balanceOf()` in pool or collateral math: the raw values differ by a factor of 1012.

### The 20 Gwei fee floor is a silent failure

Arc enforces a 20 Gwei minimum base fee. A transaction whose `maxFeePerGas` falls below it is dropped by the mempool: no error receipt, no block inclusion, no explanation. Clamp every estimate to the floor before signing.

```javascript
const MIN_FEE = ethers.parseUnits('20', 'gwei');
const feeData = await provider.getFeeData();

const maxFeePerGas = feeData.maxFeePerGas > MIN_FEE ? feeData.maxFeePerGas : MIN_FEE;
const tx = await wallet.sendTransaction({ to, value, maxFeePerGas });
```

The next block's base fee is published in the parent header's `extraData` as an 8-byte big-endian value, so you can price for the block you are about to land in rather than extrapolating from history.

### Native transfers emit logs, from two emitters

Arc implements EIP-7708, so native USDC movement emits a standard ERC-20 `Transfer` log. USDC activity therefore arrives from two emitters that share the same topic0:

| Source                          | Emitter address                              | Decimals |
| ------------------------------- | -------------------------------------------- | -------- |
| Native USDC (system, EIP-7708)  | `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` | 18       |
| ERC-20 USDC (`NativeFiatToken`) | `0x3600000000000000000000000000000000000000` | 6        |

Filter on the emitter `address`, not topic0 alone. An ERC-20 `transfer()` produces a log from *both* emitters for one movement, so an indexer that matches on topic0 double-counts it. A plain native send produces only the system log. Gas is not emitted as a `Transfer`, so derive it from the receipt.

```javascript
// Native USDC movement only, 18 decimals
const logs = await provider.send('eth_getLogs', [{
  address: '0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'],
  fromBlock: '0x0',
  toBlock: 'latest',
}]);
```

### A value transfer can revert with a funded sender

Because the native token is USDC, value movement is subject to rules that do not exist on a standard EVM chain:

- A value-bearing transfer to `0x0` reverts with `Zero address not allowed`. A zero-value transfer to `0x0` succeeds.
- Transfers to or from a blocklisted address revert. The transaction is still included and still consumes gas.
- Burning is forbidden: self-destructing to yourself with a balance, or sending value to an already self-destructed account, reverts.
- Sending value to a precompile address reverts. Sending to an address with no code succeeds and emits a `Transfer` log.

Forwarding native value to a contract is not guaranteed to succeed, which breaks a common DeFi assumption. Simulate value-bearing calls before signing.

### Header fields that do not behave like Ethereum

- `mixHash` / `PREVRANDAO` is always `0`. There is no onchain randomness, so use an oracle or VRF.
- `parentBeaconBlockRoot` is the parent execution block hash, and the EIP-4788 beacon-roots contract is omitted, so reads return empty.
- `timestamp` is non-decreasing rather than strictly increasing. Sub-second blocks can share a timestamp, so order events by block number.
- `withdrawals` is always empty.

The EIP-2935 historical block hash contract *is* deployed and functional, as are `CREATE2` and EIP-7702.

## Common Integration Patterns

### Verify the Network Before Sending Transactions

```typescript
import { JsonRpcProvider } from 'ethers';

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

const network = await provider.getNetwork();
if (network.chainId !== 5042n) {
  throw new Error(`Expected Arc (5042), received ${network.chainId}`);
}
```

### Settle on One Confirmation

Deterministic finality removes the confirmation-count logic that probabilistic chains require. Once a receipt exists, the transaction is irreversible:

```javascript
const receipt = await provider.waitForTransaction(txHash, 1);
console.log('Final in block', receipt.blockNumber);
```

Persist the block number and hash for auditability, then act on the receipt. There is no reorg path to handle.

### Keep Stateful Filters on One Backend

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection. For HTTP, preserve the `DWSESSION` cookie between requests; connection reuse alone does not pin requests to one backend. If a filter expires or the backend changes, recreate it and backfill with `eth_getLogs` from the last processed block.

## Troubleshooting

### Transaction submitted, no receipt, no error

The most likely cause is a `maxFeePerGas` below the 20 Gwei floor. Underpriced transactions are dropped by the mempool without producing an error receipt. Raise `maxFeePerGas` to at least 20 Gwei and resubmit.

### `transaction underpriced`

Same root cause, surfaced at submission instead of silently. Set `maxFeePerGas` to at least `ethers.parseUnits('20', 'gwei')`.

### `insufficient funds for gas * price + value`

On Arc, gas and value are paid from the same USDC balance. Fund the account to cover `value + maxFeePerGas × gasLimit`, not just the transfer amount.

### Balances look 1012 times too large or too small

You are mixing the 18-decimal native value with the 6-decimal ERC-20 value. Pick one interface per code path and convert explicitly at the boundary.

### Duplicate transfers in an indexer

You are counting `Transfer` logs from both the system emitter and the ERC-20 contract. Filter on the emitter address.

### `method not found` for a mining method

Arc has no mining. Use `eth_getBlockByNumber` and read `miner` if you need the block proposer.

## Related guides

- [Stablecoin L1 RPC guide: Arc, Tempo, Plasma and Stable](https://www.dwellir.com/blog/stablechain-rpc-guide)
- [Top Arc RPC providers compared](https://www.dwellir.com/blog/top-arc-rpc-providers)

## Official Resources

- [Arc documentation](https://docs.arc.io/)
- [RPC endpoints](https://docs.arc.io/arc/references/rpc-endpoints)
- [EVM differences](https://docs.arc.io/arc/references/evm-differences)
- [Gas and fees](https://docs.arc.io/arc/references/gas-and-fees)
- [USDC system events](https://docs.arc.io/arc/references/usdc-system-events)
- [Contract addresses](https://docs.arc.io/arc/references/contract-addresses)
- [Arc mainnet explorer](https://explorer.arc.io/)
- [Arc network status](https://status.arc.io/)
- [Dwellir dashboard](https://dashboard.dwellir.com)

---

## debug_traceBlock - Arc RPC Method

# debug_traceBlock - Arc RPC Method

Traces all transactions in a block on Arc by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Arc - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Arc
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Arc:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Arc blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/arc/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arc/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arc/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/arc/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Arc RPC Method

# debug_traceBlockByHash - Arc RPC Method

Traces all transactions in a block on Arc identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Arc - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Arc
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Arc:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Arc:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/arc/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arc/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arc/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/arc/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arc/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Arc RPC Method

# debug_traceBlockByNumber - Arc RPC Method

Traces all transactions in a block on Arc identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Arc - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Arc execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Arc:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Arc:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/arc/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/arc/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arc/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/arc/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Arc RPC Method

# debug_traceCall - Arc RPC Method

Traces a call on Arc without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Arc - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Arc
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x3600000000000000000000000000000000000000",
      "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x3600000000000000000000000000000000000000",
        "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x3600000000000000000000000000000000000000",
        "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x3600000000000000000000000000000000000000',
    data: '0x70a082310000000000000000000000003600000000000000000000000000000000000000'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x3600000000000000000000000000000000000000',
    data: '0x70a082310000000000000000000000003600000000000000000000000000000000000000'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x3600000000000000000000000000000000000000',
    'data': '0x70a082310000000000000000000000003600000000000000000000000000000000000000'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x3600000000000000000000000000000000000000",
        "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Arc to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Arc:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Arc:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x3600000000000000000000000000000000000000',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/arc/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arc/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/arc/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arc/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/arc/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Arc RPC Method

# debug_traceTransaction - Arc RPC Method

Traces a transaction execution on Arc by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Arc
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/arc/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/arc/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Arc RPC Method

# eth_accounts - Arc RPC Method

Returns a list of addresses owned by the client on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

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

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

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/arc/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/arc/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Arc RPC Method

# eth_blockNumber - Arc RPC Method

Returns the number of the most recent block on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_blockNumber` is fundamental for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Syncing Applications** - Keep your dApp in sync with the latest Arc blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Arc block:', blockNumber);

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

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Arc block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Arc block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Arc block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arc block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Arc:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Arc:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Arc node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Finality on Arc

Arc uses Malachite, a Tendermint-style BFT consensus with a Proof-of-Authority validator set. A block is committed only after more than two-thirds of validators pre-commit to it, which makes conflicting blocks impossible and rules out reorganizations entirely.

A transaction is therefore either unconfirmed or final, with no probabilistic middle ground. **One confirmation is enough.** Once you have a receipt, settlement is irreversible in under a second.

For integrations this means you can drop the machinery that probabilistic chains require: no confirmation-count thresholds, no reorg rollback path, no re-org-aware bookkeeping. Persist the block number and hash for auditability, then act on the receipt.

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arc/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/arc/eth_syncing) - Check if node is still syncing

---

## eth_call - Arc RPC Method

# eth_call - Arc RPC Method

Executes a new message call immediately without creating a transaction on Arc. Used for reading smart contract state.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

The `eth_call` method serves these key scenarios for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Arc
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x3600000000000000000000000000000000000000';
const walletAddress = '0x3600000000000000000000000000000000000000';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Arc. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x3600000000000000000000000000000000000000';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

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

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Arc
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Arc

## USDC balances on Arc

Arc's native token is USDC, not ETH, and the same balance is exposed through two interfaces with different precision:

| Interface | Where you read it                                           | Decimals |
| --------- | ----------------------------------------------------------- | -------- |
| Native    | `eth_getBalance`, `msg.value`, `address.balance`            | 18       |
| ERC-20    | `balanceOf` on `0x3600000000000000000000000000000000000000` | 6        |

Divide the native value by 1012 to display it as USDC. These are not two assets and there is no WETH-style wrapper, so never add the two values together or pair them against each other in pool math.

Credit and record balances from the 18-decimal native value. The ERC-20 view truncates sub-USDC fractions, so crediting from `balanceOf` records less than was actually transferred. A `balanceOf` of `0` does not mean the account is empty: a residual native balance below 1012 wei truncates to zero in the 6-decimal view.

See Arc's [stablecoin native model](https://docs.arc.io/arc/concepts/stablecoin-native-model) for the full two-interface table.

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x3600000000000000000000000000000000000000",
      "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x3600000000000000000000000000000000000000",
      "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x3600000000000000000000000000000000000000',
    '0x3600000000000000000000000000000000000000'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    contractAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")
    data := common.FromHex("0x70a082310000000000000000000000003600000000000000000000000000000000000000")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/arc/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arc/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Arc RPC Method

# eth_chainId - Arc RPC Method

Returns the chain ID used for transaction signing on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_chainId` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/arc/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/arc/eth_syncing) - Check sync status

---

## eth_estimateGas - Arc RPC Method

# eth_estimateGas - Arc RPC Method

Estimates the gas necessary to execute a transaction on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Arc
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x3600000000000000000000000000000000000000', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x3600000000000000000000000000000000000000', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Arc.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

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

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Arc may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x3600000000000000000000000000000000000000',
  '0x3600000000000000000000000000000000000000',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Arc fee market

Arc denominates gas in USDC and replaces Ethereum's per-block EIP-1559 recalculation with an EWMA-smoothed base fee, so quotes move gradually rather than spiking with a single busy block.

| Parameter            | Value                                     |
| -------------------- | ----------------------------------------- |
| Minimum base fee     | 20 Gwei (protocol floor)                  |
| Maximum base fee     | 20,000 Gwei                               |
| Base fee target      | \~$0.01 per transaction under normal load |
| Gas throughput       | 30M gas per block                         |
| Base fee destination | Paid to the block beneficiary, not burned |

Two consequences matter when you use this value:

- **Always clamp to the floor.** A quote below 20 Gwei is unusable. Transactions whose `maxFeePerGas` is under the floor are dropped by the mempool without an error receipt and never appear in a block.
- **The next block's base fee is published in advance.** Arc writes it into the parent header's `extra_data` as an 8-byte big-endian value, so you can read the upcoming base fee straight from the block header instead of extrapolating.

Because fees are dollar-denominated, show users the USDC cost rather than raw Gwei. See Arc's [gas and fees reference](https://docs.arc.io/arc/references/gas-and-fees) for the current parameter set.

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x3600000000000000000000000000000000000000",
    "to": "0x3600000000000000000000000000000000000000",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x3600000000000000000000000000000000000000",
      "to": "0x3600000000000000000000000000000000000000",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x3600000000000000000000000000000000000000', 0.1)
```

```go
package main

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

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

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

    toAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/arc/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arc/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Arc RPC Method

# eth_feeHistory - Arc RPC Method

Returns historical gas fee data on Arc, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Arc without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Arc.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Arc) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Arc fee market

Arc denominates gas in USDC and replaces Ethereum's per-block EIP-1559 recalculation with an EWMA-smoothed base fee, so quotes move gradually rather than spiking with a single busy block.

| Parameter            | Value                                     |
| -------------------- | ----------------------------------------- |
| Minimum base fee     | 20 Gwei (protocol floor)                  |
| Maximum base fee     | 20,000 Gwei                               |
| Base fee target      | \~$0.01 per transaction under normal load |
| Gas throughput       | 30M gas per block                         |
| Base fee destination | Paid to the block beneficiary, not burned |

Two consequences matter when you use this value:

- **Always clamp to the floor.** A quote below 20 Gwei is unusable. Transactions whose `maxFeePerGas` is under the floor are dropped by the mempool without an error receipt and never appear in a block.
- **The next block's base fee is published in advance.** Arc writes it into the parent header's `extra_data` as an 8-byte big-endian value, so you can read the upcoming base fee straight from the block header instead of extrapolating.

Because fees are dollar-denominated, show users the USDC cost rather than raw Gwei. See Arc's [gas and fees reference](https://docs.arc.io/arc/references/gas-and-fees) for the current parameter set.

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

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

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

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

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

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

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/arc/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/arc/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/arc/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Arc RPC Method

# eth_gasPrice - Arc RPC Method

Returns the current gas price on Arc in wei.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Arc
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Arc. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Arc, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Arc: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Arc supports dynamic fee transactions before relying on legacy gas price

## Arc fee market

Arc denominates gas in USDC and replaces Ethereum's per-block EIP-1559 recalculation with an EWMA-smoothed base fee, so quotes move gradually rather than spiking with a single busy block.

| Parameter            | Value                                     |
| -------------------- | ----------------------------------------- |
| Minimum base fee     | 20 Gwei (protocol floor)                  |
| Maximum base fee     | 20,000 Gwei                               |
| Base fee target      | \~$0.01 per transaction under normal load |
| Gas throughput       | 30M gas per block                         |
| Base fee destination | Paid to the block beneficiary, not burned |

Two consequences matter when you use this value:

- **Always clamp to the floor.** A quote below 20 Gwei is unusable. Transactions whose `maxFeePerGas` is under the floor are dropped by the mempool without an error receipt and never appear in a block.
- **The next block's base fee is published in advance.** Arc writes it into the parent header's `extra_data` as an 8-byte big-endian value, so you can read the upcoming base fee straight from the block header instead of extrapolating.

Because fees are dollar-denominated, show users the USDC cost rather than raw Gwei. See Arc's [gas and fees reference](https://docs.arc.io/arc/references/gas-and-fees) for the current parameter set.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

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

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

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

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/arc/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/arc/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/arc/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Arc RPC Method

# eth_getBalance - Arc RPC Method

Returns the balance of a given address on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getBalance` is fundamental for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Arc
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Arc
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x3600000000000000000000000000000000000000",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

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

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Arc. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Arc`);
  return balance;
}

displayBalance('0x3600000000000000000000000000000000000000');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Arc at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x3600000000000000000000000000000000000000'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Arc')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Arc')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Arc.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x3600000000000000000000000000000000000000")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## USDC balances on Arc

Arc's native token is USDC, not ETH, and the same balance is exposed through two interfaces with different precision:

| Interface | Where you read it                                           | Decimals |
| --------- | ----------------------------------------------------------- | -------- |
| Native    | `eth_getBalance`, `msg.value`, `address.balance`            | 18       |
| ERC-20    | `balanceOf` on `0x3600000000000000000000000000000000000000` | 6        |

Divide the native value by 1012 to display it as USDC. These are not two assets and there is no WETH-style wrapper, so never add the two values together or pair them against each other in pool math.

Credit and record balances from the 18-decimal native value. The ERC-20 view truncates sub-USDC fractions, so crediting from `balanceOf` records less than was actually transferred. A `balanceOf` of `0` does not mean the account is empty: a residual native balance below 1012 wei truncates to zero in the 6-decimal view.

See Arc's [stablecoin native model](https://docs.arc.io/arc/concepts/stablecoin-native-model) for the full two-interface table.

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x3600000000000000000000000000000000000000",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const address = '0x3600000000000000000000000000000000000000';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x3600000000000000000000000000000000000000'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-arc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3600000000000000000000000000000000000000")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/arc/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/arc/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Arc RPC Method

# eth_getBlockByHash - Arc RPC Method

Returns information about a block by hash on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getBlockByHash` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Arc
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Arc.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Arc.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Arc block header notes

Four header fields behave differently on Arc than on Ethereum:

- **`extraData` carries the next block's base fee**, as an 8-byte big-endian value. Read it to price a transaction for the block you are about to land in.
- **`timestamp` is non-decreasing, not strictly increasing.** Timestamps come from the proposer's wall clock at one-second granularity, and Arc produces sub-second blocks, so consecutive blocks can share a timestamp. Order events by block number, never by timestamp.
- **`mixHash` / `PREVRANDAO` is always `0`.** Arc has no beacon-chain RANDAO, so there is no onchain randomness source. The EIP-4788 beacon-roots contract is also omitted; `parentBeaconBlockRoot` is set to the parent execution block hash and reads from the beacon-roots contract return empty.
- **`withdrawals` is always empty.** Arc has no EIP-4895 withdrawals.

Blocks are final on commit. Arc's Malachite BFT consensus gives deterministic finality in under a second, so a block returned by this method will never be reorganized out.

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const blockHash = '0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockHash := common.HexToHash("0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/arc/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Arc RPC Method

# eth_getBlockByNumber - Arc RPC Method

Returns information about a block by block number on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getBlockByNumber` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Arc
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Arc with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Arc. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Arc block header notes

Four header fields behave differently on Arc than on Ethereum:

- **`extraData` carries the next block's base fee**, as an 8-byte big-endian value. Read it to price a transaction for the block you are about to land in.
- **`timestamp` is non-decreasing, not strictly increasing.** Timestamps come from the proposer's wall clock at one-second granularity, and Arc produces sub-second blocks, so consecutive blocks can share a timestamp. Order events by block number, never by timestamp.
- **`mixHash` / `PREVRANDAO` is always `0`.** Arc has no beacon-chain RANDAO, so there is no onchain randomness source. The EIP-4788 beacon-roots contract is also omitted; `parentBeaconBlockRoot` is set to the parent execution block hash and reads from the beacon-roots contract return empty.
- **`withdrawals` is always empty.** Arc has no EIP-4895 withdrawals.

Blocks are final on commit. Arc's Malachite BFT consensus gives deterministic finality in under a second, so a block returned by this method will never be reorganized out.

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

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

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

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

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/arc/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arc/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arc/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Arc RPC Method

# eth_getBlockReceipts - Arc RPC Method

Returns all transaction receipts for a block on Arc. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getBlockReceipts` is useful for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Arc, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Arc. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x1458225dfd67e21af2554d2bc03cf91d554a5a4a31eea39dea8207fb25d572f8",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arc/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arc/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Arc RPC Method

# eth_getCode - Arc RPC Method

Returns the bytecode at a given address on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getCode` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Arc
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Arc:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Arc:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x3600000000000000000000000000000000000000",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x3600000000000000000000000000000000000000",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const address = '0x3600000000000000000000000000000000000000';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x3600000000000000000000000000000000000000'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x3600000000000000000000000000000000000000")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/arc/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/arc/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Arc RPC Method

# eth_getFilterChanges - Arc RPC Method

Polls a filter on Arc for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getFilterChanges` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Arc
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x3600000000000000000000000000000000000000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x3600000000000000000000000000000000000000'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

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

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

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

    // Create a log filter
    contractAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Arc:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arc/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/arc/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/arc/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arc/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/arc/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Arc RPC Method

# eth_getFilterLogs - Arc RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Arc. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getFilterLogs` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Arc
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Native USDC Transfer logs on Arc

On a standard EVM chain a plain native send emits no log. Arc implements [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708), so native USDC movement emits a standard ERC-20 `Transfer` log from a system address. That covers plain sends, contract endowments, self-destruct transfers, and precompile-backed operations.

That means USDC activity reaches you from two emitters with different precision:

| Source                          | Emitter address                              | Decimals |
| ------------------------------- | -------------------------------------------- | -------- |
| Native USDC (system, EIP-7708)  | `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` | 18       |
| ERC-20 USDC (`NativeFiatToken`) | `0x3600000000000000000000000000000000000000` | 6        |

Both use the standard `Transfer` topic0 `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`, so filtering on topic0 alone is not enough. **Filter on the emitter `address` as well.** An ERC-20 `transfer()` call produces a log from *both* emitters for the same movement; counting both double-counts the transfer. A plain native send produces only the system log.

Gas deductions and block rewards are not emitted as `Transfer` events. Derive gas cost from the receipt (`gasUsed × effectiveGasPrice`) and attribute block rewards via `block.miner`.

See Arc's [USDC system events reference](https://docs.arc.io/arc/references/usdc-system-events) for the full event catalogue.

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x3600000000000000000000000000000000000000"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x3600000000000000000000000000000000000000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x3600000000000000000000000000000000000000'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arc/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arc/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/arc/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arc/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Arc RPC Method

# eth_getLogs - Arc RPC Method

Returns an array of all logs matching a given filter object on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Arc for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Arc
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x3600000000000000000000000000000000000000';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

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

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x3600000000000000000000000000000000000000';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Arc.

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

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Arc enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Arc, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Native USDC Transfer logs on Arc

On a standard EVM chain a plain native send emits no log. Arc implements [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708), so native USDC movement emits a standard ERC-20 `Transfer` log from a system address. That covers plain sends, contract endowments, self-destruct transfers, and precompile-backed operations.

That means USDC activity reaches you from two emitters with different precision:

| Source                          | Emitter address                              | Decimals |
| ------------------------------- | -------------------------------------------- | -------- |
| Native USDC (system, EIP-7708)  | `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` | 18       |
| ERC-20 USDC (`NativeFiatToken`) | `0x3600000000000000000000000000000000000000` | 6        |

Both use the standard `Transfer` topic0 `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`, so filtering on topic0 alone is not enough. **Filter on the emitter `address` as well.** An ERC-20 `transfer()` call produces a log from *both* emitters for the same movement; counting both double-counts the transfer. A plain native send produces only the system log.

Gas deductions and block rewards are not emitted as `Transfer` events. Derive gas cost from the receipt (`gasUsed × effectiveGasPrice`) and attribute block rewards via `block.miner`.

See Arc's [USDC system events reference](https://docs.arc.io/arc/references/usdc-system-events) for the full event catalogue.

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x3600000000000000000000000000000000000000",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x3600000000000000000000000000000000000000",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x3600000000000000000000000000000000000000",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x3600000000000000000000000000000000000000',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x3600000000000000000000000000000000000000',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arc/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arc/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Arc RPC Method

# eth_getStorageAt - Arc RPC Method

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

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getStorageAt` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **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 crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **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": [
    "0x3600000000000000000000000000000000000000",
    "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-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x3600000000000000000000000000000000000000",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x3600000000000000000000000000000000000000', '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-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x3600000000000000000000000000000000000000';

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-arc-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 = '0x3600000000000000000000000000000000000000'
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-arc-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-arc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3600000000000000000000000000000000000000")
    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 Arc:

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

const provider = new JsonRpcProvider('https://api-arc-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-arc-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 = '0x3600000000000000000000000000000000000000';
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 Arc:`);
  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/arc/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/arc/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/arc/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Arc RPC Method

# eth_getTransactionByHash - Arc RPC Method

Returns the information about a transaction by transaction hash on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getTransactionByHash` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Arc
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Arc. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Arc. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const txHash = '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arc/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arc/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Arc RPC Method

# eth_getTransactionCount - Arc RPC Method

Returns the number of transactions sent from an address on Arc, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getTransactionCount` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Arc
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x3600000000000000000000000000000000000000",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

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

## 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-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x3600000000000000000000000000000000000000",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x3600000000000000000000000000000000000000', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Arc nonce:', nonce);

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

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

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x3600000000000000000000000000000000000000'
nonce = get_transaction_count(address)
print(f'Arc nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x3600000000000000000000000000000000000000")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Arc nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Arc:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x3600000000000000000000000000000000000000');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arc/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/arc/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arc/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arc/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Arc RPC Method

# eth_getTransactionReceipt - Arc RPC Method

Returns the receipt of a transaction by transaction hash on Arc. Receipt is only available for mined transactions.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_getTransactionReceipt` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Arc and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Arc. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Arc, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Finality on Arc

Arc uses Malachite, a Tendermint-style BFT consensus with a Proof-of-Authority validator set. A block is committed only after more than two-thirds of validators pre-commit to it, which makes conflicting blocks impossible and rules out reorganizations entirely.

A transaction is therefore either unconfirmed or final, with no probabilistic middle ground. **One confirmation is enough.** Once you have a receipt, settlement is irreversible in under a second.

For integrations this means you can drop the machinery that probabilistic chains require: no confirmation-count thresholds, no reorg rollback path, no re-org-aware bookkeeping. Persist the block number and hash for auditability, then act on the receipt.

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arc/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/arc/eth_getLogs) - Query logs by filter

---

## eth_maxPriorityFeePerGas - Arc RPC Method

# eth_maxPriorityFeePerGas - Arc RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Arc. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Arc
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Arc priority fee:', priorityFeeGwei, 'Gwei');

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

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Arc priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

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

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

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

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Arc priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Arc:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Arc:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Arc fee market

Arc denominates gas in USDC and replaces Ethereum's per-block EIP-1559 recalculation with an EWMA-smoothed base fee, so quotes move gradually rather than spiking with a single busy block.

| Parameter            | Value                                     |
| -------------------- | ----------------------------------------- |
| Minimum base fee     | 20 Gwei (protocol floor)                  |
| Maximum base fee     | 20,000 Gwei                               |
| Base fee target      | \~$0.01 per transaction under normal load |
| Gas throughput       | 30M gas per block                         |
| Base fee destination | Paid to the block beneficiary, not burned |

Two consequences matter when you use this value:

- **Always clamp to the floor.** A quote below 20 Gwei is unusable. Transactions whose `maxFeePerGas` is under the floor are dropped by the mempool without an error receipt and never appear in a block.
- **The next block's base fee is published in advance.** Arc writes it into the parent header's `extra_data` as an 8-byte big-endian value, so you can read the upcoming base fee straight from the block header instead of extrapolating.

Because fees are dollar-denominated, show users the USDC cost rather than raw Gwei. See Arc's [gas and fees reference](https://docs.arc.io/arc/references/gas-and-fees) for the current parameter set.

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/arc/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/arc/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/arc/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/arc/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_newBlockFilter - Arc RPC Method

# eth_newBlockFilter - Arc RPC Method

Creates a filter on Arc that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_newBlockFilter` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Block Monitoring** - Detect new blocks on Arc as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

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

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

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Arc:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arc/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arc/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/arc/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/arc/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Arc RPC Method

# eth_newFilter - Arc RPC Method

Creates a filter object on Arc based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_newFilter` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Event Monitoring** - Subscribe to specific contract events on Arc such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Native USDC Transfer logs on Arc

On a standard EVM chain a plain native send emits no log. Arc implements [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708), so native USDC movement emits a standard ERC-20 `Transfer` log from a system address. That covers plain sends, contract endowments, self-destruct transfers, and precompile-backed operations.

That means USDC activity reaches you from two emitters with different precision:

| Source                          | Emitter address                              | Decimals |
| ------------------------------- | -------------------------------------------- | -------- |
| Native USDC (system, EIP-7708)  | `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` | 18       |
| ERC-20 USDC (`NativeFiatToken`) | `0x3600000000000000000000000000000000000000` | 6        |

Both use the standard `Transfer` topic0 `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`, so filtering on topic0 alone is not enough. **Filter on the emitter `address` as well.** An ERC-20 `transfer()` call produces a log from *both* emitters for the same movement; counting both double-counts the transfer. A plain native send produces only the system log.

Gas deductions and block rewards are not emitted as `Transfer` events. Derive gas cost from the receipt (`gasUsed × effectiveGasPrice`) and attribute block rewards via `block.miner`.

See Arc's [USDC system events reference](https://docs.arc.io/arc/references/usdc-system-events) for the full event catalogue.

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x3600000000000000000000000000000000000000",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x3600000000000000000000000000000000000000",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x3600000000000000000000000000000000000000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x3600000000000000000000000000000000000000',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    contractAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Arc:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x3600000000000000000000000000000000000000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arc/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/arc/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/arc/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arc/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/arc/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Arc RPC Method

# eth_newPendingTransactionFilter - Arc RPC Method

Creates a filter on Arc that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Mempool Monitoring** - Observe unconfirmed transactions on Arc to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Arc...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Arc:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arc/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/arc/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/arc/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/arc/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Arc RPC Method

# eth_protocolVersion - Arc RPC Method

Returns the current Ethereum protocol version used by the Arc node.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_protocolVersion` is useful for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Arc protocol version:', version);

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

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Arc protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Arc protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Arc protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arc protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Arc nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/arc/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/arc/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/arc/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Arc RPC Method

# eth_sendRawTransaction - Arc RPC Method

Submits a pre-signed transaction for broadcast to Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Arc
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x3600000000000000000000000000000000000000', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Arc mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Arc submission rules

Arc accepts standard signed Ethereum transactions, but three rules differ from a normal EVM chain and each one produces a different failure mode.

**Set `maxFeePerGas` to at least 20 Gwei.** This is Arc's protocol base fee floor. A transaction below it is silently dropped by the mempool: `eth_sendRawTransaction` may still return a hash, but no receipt is ever produced and the transaction never appears in a block. Clamp your fee estimate to the floor before signing rather than treating a missing receipt as a network problem.

**Do not send blob transactions.** Arc does not implement EIP-4844, and the mempool rejects type-3 transactions.

**A value transfer can revert even with sufficient balance.** Because the native token is USDC, value movement is subject to rules that do not exist elsewhere:

- A value-bearing transfer to `0x0` reverts with `Zero address not allowed` (a zero-value transfer to `0x0` succeeds).
- A transfer to or from a blocklisted address reverts. The transaction is still included and still consumes gas.
- Burning is forbidden: self-destructing to yourself with a balance, or sending value to an account that has already self-destructed, reverts.
- Sending value to a precompile address reverts. Sending to an address with no code succeeds.

Simulate value-bearing calls with `eth_call` or `eth_estimateGas` before signing, and do not assume that forwarding native value to a contract always succeeds.

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/arc/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x3600000000000000000000000000000000000000")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/arc/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/arc/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/arc/eth_getTransactionReceipt) - Get transaction result

---

## eth_syncing - Arc RPC Method

# eth_syncing - Arc RPC Method

Returns the sync status of your Arc node - either `false` when fully synced, or an object describing the sync progress.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_syncing` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Arc node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Arc node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Arc node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/arc/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/arc/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/arc/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/arc/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Arc RPC Method

# eth_uninstallFilter - Arc RPC Method

Removes a filter on Arc that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`eth_uninstallFilter` is important for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/arc/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/arc/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/arc/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/arc/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/arc/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Arc RPC Method

# net_listening - Arc RPC Method

Checks whether the connected Arc client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`net_listening` is useful for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

try {
  const listening = await provider.send('net_listening', []);
  console.log('Arc node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Arc node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Arc node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/arc/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/arc/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/arc/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/arc/web3_clientVersion) - Get node client info

---

## net_peerCount - Arc RPC Method

# net_peerCount - Arc RPC Method

Returns the number of peers currently connected to your Arc node.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`net_peerCount` is important for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Arc deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Arc peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Arc peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Arc peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Arc nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/arc/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/arc/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/arc/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/arc/web3_clientVersion) - Get node client info

---

## net_version - Arc RPC Method

# net_version - Arc RPC Method

Returns the current network ID on Arc as a decimal string. The network ID identifies which network the node is connected to.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`net_version` is essential for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Endpoint Identification** - Confirm your application is connected to the expected Arc network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const networkId = await provider.send('net_version', []);
console.log('Arc network ID:', networkId);

// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Arc network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arc network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/arc/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/arc/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/arc/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/arc/eth_syncing) - Check node sync progress

---

## rpc_modules - Arc RPC Method

# rpc_modules - Arc RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Arc endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`rpc_modules` is useful for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Arc namespace availability

Dwellir's Arc mainnet endpoint serves the `eth_*`, `net_*`, `web3_*`, `rpc_*`, `debug_*`, and `trace_*` namespaces. The `debug_*` and `trace_*` calls run on archive nodes. The `txpool_*` namespace is not enabled, so calls to it return `-32601 Method not found`. Arc-specific reads such as `arc_getCertificate` are available.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "debug": "1.0",
    "eth": "1.0",
    "net": "1.0",
    "rpc": "1.0",
    "trace": "1.0",
    "web3": "1.0"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/arc/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/arc/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/arc/trace_transaction) - Trace namespace example

---

## trace_block - Arc RPC Method

# trace_block - Arc RPC Method

Returns traces for all transactions in a block on Arc.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Arc
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Arc chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/arc/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/arc/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/arc/trace_get) - Get a specific trace by index

---

## trace_call - Arc RPC Method

# trace_call - Arc RPC Method

Traces a call without creating a transaction on Arc, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Arc
- **Pre-execution analysis** - Test contract interactions without spending gas for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x3600000000000000000000000000000000000000",
      "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x3600000000000000000000000000000000000000", "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const result = await provider.send('trace_call', [
  {
    to: '0x3600000000000000000000000000000000000000',
    data: '0x70a082310000000000000000000000003600000000000000000000000000000000000000'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x3600000000000000000000000000000000000000',
        'data': '0x70a082310000000000000000000000003600000000000000000000000000000000000000'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/arc/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/arc/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/arc/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Arc RPC Method

# trace_callMany - Arc RPC Method

Traces multiple calls in sequence on Arc, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Arc
- **Historical state comparison** - Compare how the same call would execute at different points in Arc chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x3600000000000000000000000000000000000000", "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"}, ["trace"]],
      [{"to": "0x3600000000000000000000000000000000000000", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x3600000000000000000000000000000000000000", "data": "0x70a082310000000000000000000000003600000000000000000000000000000000000000"}, ["trace"]],
        [{"to": "0x3600000000000000000000000000000000000000", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x3600000000000000000000000000000000000000', data: '0x70a082310000000000000000000000003600000000000000000000000000000000000000' }, ['trace']],
    [{ to: '0x3600000000000000000000000000000000000000', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x3600000000000000000000000000000000000000', 'data': '0x70a082310000000000000000000000003600000000000000000000000000000000000000'}, ['trace']],
        [{'to': '0x3600000000000000000000000000000000000000', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/arc/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/arc/eth_call) - Execute call without trace

---

## trace_filter - Arc RPC Method

# trace_filter - Arc RPC Method

Returns traces matching a filter on Arc.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Arc
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x3600000000000000000000000000000000000000"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x3600000000000000000000000000000000000000"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x3600000000000000000000000000000000000000'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x3600000000000000000000000000000000000000'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/arc/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/arc/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/arc/eth_getLogs) - Filter event logs

---

## trace_get - Arc RPC Method

# trace_get - Arc RPC Method

Returns a trace at a specific position within a transaction on Arc.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Arc
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const trace = await provider.send('trace_get', [
  '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/arc/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/arc/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Arc RPC Method

# trace_replayBlockTransactions - Arc RPC Method

Replays all transactions in a block on Arc and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Arc
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Arc chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/arc/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/arc/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/arc/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Arc RPC Method

# trace_replayTransaction - Arc RPC Method

Replays a transaction on Arc and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Arc
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const result = await provider.send('trace_replayTransaction', [
  '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/arc/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/arc/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/arc/trace_block) - Get all traces in a block

---

## trace_transaction - Arc RPC Method

# trace_transaction - Arc RPC Method

Returns all traces for a specific transaction on Arc.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for crossborder settlement, merchant payments, institutional clearing, and USDC-denominated financial applications
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Arc
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const traces = await provider.send('trace_transaction', [
  '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x3a2417718cf029777eb22580966a35be868e7f82cbdd26c6d4128fb015266f64'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/arc/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/arc/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/arc/trace_filter) - Filter traces by criteria

---

## web3_clientVersion - Arc RPC Method

# web3_clientVersion - Arc RPC Method

Returns the current client software version string for your Arc node, including the client name, version number, OS, and runtime.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

## When to Use This Method

`web3_clientVersion` is valuable for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Arc client:', clientVersion);

// Using fetch
const response = await fetch('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Arc client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Arc client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/arc/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/arc/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/arc/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/arc/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Arc RPC Method

# web3_sha3 - Arc RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Arc.

> **Why Arc?** Build on Circle's stablecoin-native Layer 1 where USDC is the gas token and BFT consensus gives sub-second deterministic finality with USDC as the native gas token, sub-second irreversible finality, an EWMA-smoothed fee market with a 20 Gwei floor, and EIP-7708 Transfer logs for native value movement.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for payment platforms, stablecoin issuers, exchange and treasury teams, and Solidity developers building on Arc:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

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

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

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

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

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-arc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/arc/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/arc/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/arc/web3_clientVersion) - Get node client version

---

## Asset Hub - Polkadot Asset Management

# Asset Hub - Polkadot Asset Management

## Asset Hub RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Asset Hub supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Asset Hub?

Asset Hub is Polkadot's native system parachain designed for efficient asset creation, management, and transfers. As a core infrastructure parachain, Asset Hub provides low-cost asset operations and seamless integration with the broader Polkadot ecosystem.

### **Native Asset Management**

- **Asset creation** - Mint fungible and non-fungible tokens natively
- **Low transaction costs** - Optimized for high-frequency asset operations
- **Cross-chain transfers** - Seamless XCM integration with all parachains
- **DOT integration** - Native support for Polkadot's main token

### **Multi-Network Support**

- **Polkadot Asset Hub** - Main network for production applications
- **Kusama Asset Hub** - Canary network for testing and experimentation
- **Westend Asset Hub** - Test network for development and staging
- **Paseo Asset Hub** - Community-operated testnet tracking Polkadot releases
- **Polkadot Sidecar** - Managed Sidecar API surface for REST-friendly data access

### **Performance & Efficiency**

- **Fast finality** - \~6 second block times with instant finality
- **Minimal fees** - Optimized for micro-transactions and asset operations
- **Substrate runtime** - Built on battle-tested Polkadot technology
- **XCM native** - First-class cross-chain messaging support

## Quick Start with Asset Hub

Connect to Asset Hub networks with Dwellir's reliable endpoints:

Dwellir serves Asset Hub across every public Polkadot environment:

- **Asset Hub Polkadot** – `wss://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY`
- **Asset Hub Kusama** – `wss://api-asset-hub-kusama.n.dwellir.com/YOUR_API_KEY`
- **Asset Hub Westend** – `https://api-asset-hub-westend.n.dwellir.com/YOUR_API_KEY`
- **Asset Hub Paseo** – `https://api-asset-hub-paseo.n.dwellir.com/YOUR_API_KEY`
- **Polkadot Sidecar** – `https://api-asset-hub-polkadot-sidecar.n.dwellir.com/YOUR_API_KEY`

The Sidecar tab exposes a managed Polkadot Sidecar deployment so you can issue REST requests (for example `/accounts` or `/blocks`) without running additional infrastructure.

### Installation & Setup

Direct JSON-RPC
Polkadot.js
Substrate API
Python (py-substrate-interface)

```bash
# Get chain information
curl -X POST https://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'

# Get latest finalized block
curl -X POST https://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'

# Query account balance
curl -X POST https://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"],
    "id": 1
  }'
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

// Connect to Asset Hub Polkadot
const provider = new WsProvider('wss://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Verify connection
const chain = await api.rpc.system.chain();
const version = await api.rpc.system.version();
console.log(`Connected to ${chain} v${version}`);

// Get the latest block
const hash = await api.rpc.chain.getFinalizedHead();
const block = await api.rpc.chain.getBlock(hash);
console.log(`Latest block: #${block.block.header.number}`);

// Query account balance
const account = 'ACCOUNT_ADDRESS';
const balance = await api.query.system.account(account);
console.log(`Free balance: ${balance.data.free.toString()}`);
```

```typescript
import { createClient } from '@substrate/api';

// Connect to Asset Hub
const client = createClient({
  chainSpec: {
    genesisHash: '0x68d56f15f85d3136970ec16946040bc1752654e906147f7e43e9d539d7c3de2f',
    rpcUrls: ['https://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY']
  }
});

// Query chain information
const chainInfo = await client.getChainHead();
console.log('Current head:', chainInfo.hash);

// Get asset information
const assetId = 1000; // USDT on Asset Hub
const assetDetails = await client.query({
  type: 'assets',
  method: 'asset',
  args: [assetId]
});
```

```python
from substrateinterface import SubstrateInterface

# Connect to Asset Hub Polkadot
substrate = SubstrateInterface(
    url="wss://api-asset-hub-polkadot.n.dwellir.com/YOUR_API_KEY"
)

# Get chain information
chain_name = substrate.rpc_request("system_chain", [])
print(f"Connected to: {chain_name['result']}")

# Query account balance
account_info = substrate.query(
    module='System',
    storage_function='Account',
    params=['ACCOUNT_ADDRESS']
)

print(f"Free balance: {account_info['data']['free']}")

# Query asset details
asset_id = 1000  # USDT
asset_details = substrate.query(
    module='Assets',
    storage_function='Asset',
    params=[asset_id]
)

if asset_details:
    print(f"Asset name: {asset_details['name']}")
    print(f"Asset symbol: {asset_details['symbol']}")
    print(f"Decimals: {asset_details['decimals']}")
```

## Network Information

| Parameter    | Value         | Details            |
| ------------ | ------------- | ------------------ |
| Genesis Hash | 0x68d56f15... | Polkadot Asset Hub |
| Block Time   | 6 seconds     | Instant finality   |
| Native Token | DOT           | Polkadot token     |
| Parachain ID | 1000          | System parachain   |

### Network Details

| Parameter                       | Value                                       | Details |
| ------------------------------- | ------------------------------------------- | ------- |
| Polkadot Asset Hub Parachain ID | 1000                                        |         |
| Kusama Asset Hub Parachain ID   | 1000                                        |         |
| Westend Asset Hub Parachain ID  | 1000                                        |         |
| Native Token                    | DOT (Polkadot), KSM (Kusama), WND (Westend) |         |
| Consensus                       | Nominated Proof of Stake (via Relay Chain)  |         |
| Finality                        | Instant (via GRANDPA finality gadget)       |         |

## Core Features

### **Asset Management**

Create and manage fungible assets with native support:

```typescript
// Create a new asset
const createAsset = async (api, signer, assetId, admin, minBalance) => {
  const tx = api.tx.assets.create(assetId, admin, minBalance);
  const hash = await tx.signAndSend(signer);
  return hash;
};

// Set asset metadata
const setMetadata = async (api, signer, assetId, name, symbol, decimals) => {
  const tx = api.tx.assets.setMetadata(assetId, name, symbol, decimals);
  const hash = await tx.signAndSend(signer);
  return hash;
};

// Mint assets
const mintAsset = async (api, signer, assetId, beneficiary, amount) => {
  const tx = api.tx.assets.mint(assetId, beneficiary, amount);
  const hash = await tx.signAndSend(signer);
  return hash;
};
```

### **NFT Support**

Work with non-fungible tokens using the Uniques pallet:

```typescript
// Create an NFT collection
const createCollection = async (api, signer, collectionId, admin) => {
  const tx = api.tx.uniques.create(collectionId, admin);
  const hash = await tx.signAndSend(signer);
  return hash;
};

// Mint an NFT
const mintNFT = async (api, signer, collectionId, itemId, owner) => {
  const tx = api.tx.uniques.mint(collectionId, itemId, owner);
  const hash = await tx.signAndSend(signer);
  return hash;
};

// Set NFT metadata
const setNFTMetadata = async (api, signer, collectionId, itemId, data) => {
  const tx = api.tx.uniques.setMetadata(collectionId, itemId, data, false);
  const hash = await tx.signAndSend(signer);
  return hash;
};
```

### **Cross-Chain Transfers (XCM)**

Send assets across the Polkadot ecosystem:

```typescript
// Transfer DOT to another parachain
const xcmTransfer = async (api, signer, dest, beneficiary, amount) => {
  const destination = {
    V3: {
      parents: 1,
      interior: {
        X1: {
          Parachain: dest // Destination parachain ID
        }
      }
    }
  };

  const account = {
    V3: {
      parents: 0,
      interior: {
        X1: {
          AccountId32: {
            network: null,
            id: beneficiary
          }
        }
      }
    }
  };

  const assets = {
    V3: [
      {
        id: {
          Concrete: {
            parents: 1,
            interior: 'Here'
          }
        },
        fun: {
          Fungible: amount
        }
      }
    ]
  };

  const tx = api.tx.polkadotXcm.limitedReserveTransferAssets(
    destination,
    account,
    assets,
    0,
    'Unlimited'
  );

  const hash = await tx.signAndSend(signer);
  return hash;
};
```

## Common Integration Patterns

### **Multi-Asset Wallet**

Build wallets supporting multiple Asset Hub tokens:

```typescript
class AssetHubWallet {
  constructor(api, address) {
    this.api = api;
    this.address = address;
  }

  async getAllBalances() {
    const balances = {};

    // Get DOT balance
    const account = await this.api.query.system.account(this.address);
    balances.DOT = {
      free: account.data.free.toString(),
      reserved: account.data.reserved.toString(),
      symbol: 'DOT',
      decimals: 10
    };

    // Get asset balances
    const assets = await this.api.query.assets.account.entries(this.address);

    for (const [key, balance] of assets) {
      const assetId = key.args[0].toString();
      const metadata = await this.api.query.assets.metadata(assetId);

      balances[metadata.symbol.toString()] = {
        free: balance.unwrap().balance.toString(),
        assetId,
        symbol: metadata.symbol.toString(),
        decimals: metadata.decimals.toNumber()
      };
    }

    return balances;
  }

  async transferAsset(assetId, recipient, amount) {
    let tx;

    if (assetId === 'DOT') {
      // Native DOT transfer
      tx = this.api.tx.balances.transferKeepAlive(recipient, amount);
    } else {
      // Asset transfer
      tx = this.api.tx.assets.transferKeepAlive(assetId, recipient, amount);
    }

    return tx;
  }
}
```

### **Asset Analytics**

Track asset metrics and usage:

```typescript
class AssetAnalytics {
  constructor(api) {
    this.api = api;
  }

  async getAssetInfo(assetId) {
    const [details, metadata] = await Promise.all([
      this.api.query.assets.asset(assetId),
      this.api.query.assets.metadata(assetId)
    ]);

    if (details.isNone) {
      throw new Error(`Asset ${assetId} not found`);
    }

    const assetDetails = details.unwrap();

    return {
      id: assetId,
      name: metadata.name.toString(),
      symbol: metadata.symbol.toString(),
      decimals: metadata.decimals.toNumber(),
      supply: assetDetails.supply.toString(),
      accounts: assetDetails.accounts.toNumber(),
      sufficients: assetDetails.sufficients.toNumber(),
      owner: assetDetails.owner.toString(),
      issuer: assetDetails.issuer.toString(),
      admin: assetDetails.admin.toString(),
      freezer: assetDetails.freezer.toString(),
      minBalance: assetDetails.minBalance.toString(),
      isSufficient: assetDetails.isSufficient.toBoolean()
    };
  }

  async getTopAssets(limit = 10) {
    const assets = [];

    // Get all assets
    const assetEntries = await this.api.query.assets.asset.entries();

    for (const [key, details] of assetEntries) {
      const assetId = key.args[0].toString();
      const metadata = await this.api.query.assets.metadata(assetId);

      assets.push({
        id: assetId,
        symbol: metadata.symbol.toString(),
        supply: details.unwrap().supply.toString(),
        accounts: details.unwrap().accounts.toNumber()
      });
    }

    // Sort by number of accounts (popularity)
    return assets
      .sort((a, b) => b.accounts - a.accounts)
      .slice(0, limit);
  }
}
```

### **NFT Marketplace Integration**

Integrate with NFT collections:

```typescript
class NFTCollection {
  constructor(api, collectionId) {
    this.api = api;
    this.collectionId = collectionId;
  }

  async getCollectionInfo() {
    const [details, metadata] = await Promise.all([
      this.api.query.uniques.class(this.collectionId),
      this.api.query.uniques.classMetadataOf(this.collectionId)
    ]);

    return {
      id: this.collectionId,
      owner: details.unwrap().owner.toString(),
      issuer: details.unwrap().issuer.toString(),
      admin: details.unwrap().admin.toString(),
      freezer: details.unwrap().freezer.toString(),
      totalDeposit: details.unwrap().totalDeposit.toString(),
      freeHolding: details.unwrap().freeHolding.toBoolean(),
      instances: details.unwrap().instances.toNumber(),
      instanceMetadatas: details.unwrap().instanceMetadatas.toNumber(),
      attributes: details.unwrap().attributes.toNumber(),
      isFrozen: details.unwrap().isFrozen.toBoolean(),
      metadata: metadata.isSome ? metadata.unwrap().data.toString() : null
    };
  }

  async getAllItems() {
    const items = [];
    const itemEntries = await this.api.query.uniques.asset.entries();

    for (const [key, details] of itemEntries) {
      const [collectionId, itemId] = key.args;

      if (collectionId.toString() === this.collectionId.toString()) {
        const metadata = await this.api.query.uniques.instanceMetadataOf(
          collectionId,
          itemId
        );

        items.push({
          collectionId: collectionId.toString(),
          itemId: itemId.toString(),
          owner: details.unwrap().owner.toString(),
          approved: details.unwrap().approved.isSome
            ? details.unwrap().approved.unwrap().toString()
            : null,
          isFrozen: details.unwrap().isFrozen.toBoolean(),
          deposit: details.unwrap().deposit.toString(),
          metadata: metadata.isSome ? metadata.unwrap().data.toString() : null
        });
      }
    }

    return items;
  }
}
```

## Performance Optimization

### 1. **Efficient State Queries**

Batch multiple queries for better performance:

```typescript
async function batchQueries(api, queries) {
  const results = await Promise.all(queries.map(query => {
    if (query.type === 'storage') {
      return api.query[query.module][query.method](https://www.dwellir.com/docs/...query.args);
    } else if (query.type === 'rpc') {
      return api.rpc[query.module][query.method](https://www.dwellir.com/docs/...query.args);
    }
  }));

  return results;
}

// Example usage
const queries = [
  { type: 'storage', module: 'system', method: 'account', args: [address] },
  { type: 'storage', module: 'assets', method: 'asset', args: [1000] },
  { type: 'rpc', module: 'chain', method: 'getFinalizedHead', args: [] }
];

const [account, asset, head] = await batchQueries(api, queries);
```

### 2. **Event Subscription**

Monitor blockchain events efficiently:

```typescript
async function subscribeToAssetEvents(api, callback) {
  const unsubscribe = await api.query.system.events((events) => {
    events.forEach((record) => {
      const { event } = record;

      if (api.events.assets.Transferred.is(event)) {
        const [assetId, from, to, amount] = event.data;
        callback({
          type: 'AssetTransferred',
          assetId: assetId.toString(),
          from: from.toString(),
          to: to.toString(),
          amount: amount.toString()
        });
      } else if (api.events.assets.Created.is(event)) {
        const [assetId, creator, owner] = event.data;
        callback({
          type: 'AssetCreated',
          assetId: assetId.toString(),
          creator: creator.toString(),
          owner: owner.toString()
        });
      }
    });
  });

  return unsubscribe;
}
```

## Developer Resources

### **Official Resources**

- [Polkadot Developer Docs](https://docs.polkadot.com/polkadot-protocol/architecture/system-chains/asset-hub/)
- [Asset Hub Wiki](https://wiki.polkadot.com/learn/learn-assets/)
- [Substrate Documentation](https://docs.substrate.io/)

### **Developer Tools**

- [Polkadot.js Apps](https://polkadot.js.org/apps/) - Web interface for Asset Hub
- [Polkadot.js API](https://polkadot.js.org/docs/) - JavaScript SDK
- [Subxt](https://github.com/paritytech/subxt) - Rust SDK for Substrate chains
- [py-substrate-interface](https://github.com/polkascan/py-substrate-interface) - Python SDK

### **Block Explorers**

- [Polkadot.js Apps Explorer](https://polkadot.js.org/apps/#/explorer)
- [Subscan Asset Hub](https://assethub-polkadot.subscan.io/)

### **Example Projects**

- [Asset Transfer Tools](https://github.com/paritytech/asset-transfer-api)
- [XCM Tools](https://docs.polkadot.com/develop/toolkit/interoperability/xcm-tools/)
- [Asset Hub Examples](https://github.com/bee344/asset-hub-examples)

### Need Help?

- **Email**: <support@dwellir.com>
- **Polkadot Wiki**: [wiki.polkadot.network](https://wiki.polkadot.network)
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Community**: [Polkadot Discord](https://discord.gg/polkadot)

***

*Build the future of cross-chain asset management on Asset Hub with Dwellir's reliable infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## author_pendingExtrinsics - Asset Hub RPC Method

# author_pendingExtrinsics - Asset Hub RPC Method

Returns all pending extrinsics currently in the transaction pool on Asset Hub. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`author_pendingExtrinsics` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Asset Hub
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Asset Hub transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/asset-hub/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/asset-hub/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/asset-hub/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Asset Hub RPC Method

# author_rotateKeys - Asset Hub RPC Method

Generate a new set of session keys on Asset Hub. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`author_rotateKeys` is critical for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Validator Setup** - Generate initial session keys when setting up a new validator on native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Asset Hub:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/asset-hub/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/asset-hub/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Asset Hub RPC Method

# author_submitAndWatchExtrinsic - Asset Hub RPC Method

Submits a signed extrinsic to Asset Hub and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Asset Hub
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

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

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://asset-hub-polkadot-rpc.n.dwellir.com

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://asset-hub-polkadot-rpc.n.dwellir.com');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://asset-hub-polkadot-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://asset-hub-polkadot-rpc.n.dwellir.com").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/asset-hub/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/asset-hub/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/asset-hub/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Asset Hub RPC Method

# author_submitExtrinsic - Asset Hub RPC Method

Submits a fully signed extrinsic to Asset Hub for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`author_submitExtrinsic` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Token Transfers** -- Send native tokens or assets between accounts on Asset Hub
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

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

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://asset-hub-polkadot-rpc.n.dwellir.com").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/asset-hub/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/asset-hub/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Asset Hub RPC Method

# beefy_getFinalizedHead - Asset Hub RPC Method

Returns the block hash of the latest BEEFY-finalized block on Asset Hub. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`beefy_getFinalizedHead` is important for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

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

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/asset-hub/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Asset Hub RPC Method

# chain_getBlock - Asset Hub RPC Method

Retrieves complete block information from Asset Hub, including the block header, extrinsics, and justifications.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://asset-hub-polkadot-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://asset-hub-polkadot-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/asset-hub/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/asset-hub/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Asset Hub RPC Method

# chain_getBlockHash - Asset Hub RPC Method

Returns the block hash for a given block number on Asset Hub. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`chain_getBlockHash` is fundamental for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Asset Hub
- **Block Navigation** - Navigate the blockchain history for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Asset Hub
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Asset Hub for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Asset Hub state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Asset Hub network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/asset-hub/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Asset Hub RPC Method

# chain_getFinalizedHead - Asset Hub RPC Method

Returns the hash of the last finalized block on Asset Hub. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`chain_getFinalizedHead` is critical for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Asset Hub
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://asset-hub-polkadot-rpc.n.dwellir.com', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Asset Hub:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/asset-hub/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/asset-hub/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Asset Hub RPC Method

# chain_getHeader - Asset Hub RPC Method

Returns the block header for a given hash on Asset Hub. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`chain_getHeader` is ideal for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Asset Hub
- **Chain Synchronization** - Track block production and monitor chain progress for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Asset Hub:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Asset Hub chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Asset Hub block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/asset-hub/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Asset Hub RPC Method

# chain_subscribeFinalizedHeads - Asset Hub RPC Method

Subscribe to receive notifications when blocks are finalized on Asset Hub. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Exchange Deposits** - Only credit funds after finalization for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://asset-hub-polkadot-rpc.n.dwellir.com`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://asset-hub-polkadot-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://asset-hub-polkadot-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Asset Hub:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/asset-hub/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Asset Hub RPC Method

# chain_subscribeNewHeads - Asset Hub RPC Method

Subscribe to receive notifications when new block headers are produced on Asset Hub. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`chain_subscribeNewHeads` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Block Monitoring** - Track new blocks in real time on Asset Hub for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://asset-hub-polkadot-rpc.n.dwellir.com`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://asset-hub-polkadot-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://asset-hub-polkadot-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Asset Hub as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Asset Hub:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/asset-hub/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/asset-hub/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Asset Hub RPC Method

# grandpa_roundState - Asset Hub RPC Method

Returns the state of the current GRANDPA finality round on Asset Hub when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`grandpa_roundState` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Asset Hub, critical for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/asset-hub/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/asset-hub/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Asset Hub RPC Method

# payment_queryFeeDetails - Asset Hub RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Asset Hub. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`payment_queryFeeDetails` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Asset Hub
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/asset-hub/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/asset-hub/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/asset-hub/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/asset-hub/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Asset Hub RPC Method

# payment_queryInfo - Asset Hub RPC Method

Estimates the fee for an encoded extrinsic on Asset Hub. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`payment_queryInfo` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Asset Hub
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/asset-hub/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/asset-hub/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/asset-hub/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/asset-hub/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Asset Hub RPC Method

# rpc_methods - Asset Hub RPC Method

Returns a list of all RPC methods exposed by the Asset Hub node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`rpc_methods` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Asset Hub node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Asset Hub endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://asset-hub-polkadot-rpc.n.dwellir.com', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Asset Hub endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/asset-hub/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/asset-hub/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Asset Hub RPC Method

# state_call - Asset Hub RPC Method

Calls a runtime API function on Asset Hub and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`state_call` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/asset-hub/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/asset-hub/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/asset-hub/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-asset-hub-polkadot.n.dwellir.com"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-asset-hub-polkadot.n.dwellir.com', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-asset-hub-polkadot.n.dwellir.com');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-asset-hub-polkadot.n.dwellir.com') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/asset-hub/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/asset-hub/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - Asset Hub RPC Method

# state_getKeysPaged - Asset Hub RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Asset Hub. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`state_getKeysPaged` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Asset Hub
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://asset-hub-polkadot-rpc.n.dwellir.com";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/asset-hub/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/asset-hub/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Asset Hub RPC Method

# state_getMetadata - Asset Hub RPC Method

Returns the runtime metadata for Asset Hub as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`state_getMetadata` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Asset Hub
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Asset Hub:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Asset Hub:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/asset-hub/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/asset-hub/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Asset Hub RPC Method

# state_getRuntimeVersion - Asset Hub RPC Method

Returns the runtime version information for Asset Hub, including the spec name, spec version, implementation version, and supported API versions.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`state_getRuntimeVersion` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Asset Hub
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Asset Hub in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/asset-hub/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Asset Hub RPC Method

# state_getStorage - Asset Hub RPC Method

Returns the SCALE-encoded storage value for a given key on Asset Hub. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`state_getStorage` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Asset Hub
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/asset-hub/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/asset-hub/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Asset Hub RPC Method

# state_queryStorageAt - Asset Hub RPC Method

Queries multiple storage keys at a specific block on Asset Hub, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`state_queryStorageAt` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Asset Hub
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/asset-hub/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/asset-hub/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/asset-hub/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/asset-hub/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Asset Hub RPC Method

# system_chain - Asset Hub RPC Method

Returns the chain name of the Asset Hub network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`system_chain` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Network Verification** -- Confirm your application is connected to the correct Asset Hub network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Asset Hub"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://asset-hub-polkadot-rpc.n.dwellir.com', 'Asset Hub');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/asset-hub/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/asset-hub/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/asset-hub/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/asset-hub/rpc_methods) -- List all available RPC methods

---

## system_health - Asset Hub RPC Method

# system_health - Asset Hub RPC Method

Returns the health status of the Asset Hub node, including peer count, sync state, and whether the node expects to have peers.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`system_health` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Asset Hub
- **Load Balancing** - Route requests only to healthy, fully synced nodes for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://asset-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://asset-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Asset Hub:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Asset Hub nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://asset-hub-polkadot-rpc.n.dwellir.com')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/asset-hub/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Asset Hub RPC Method

# system_name - Asset Hub RPC Method

Returns the node implementation name on Asset Hub. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`system_name` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Asset Hub
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Asset Hub node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Asset Hub node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Asset Hub node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
name = substrate.rpc_request('system_name', [])['result']
print(f'Asset Hub node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Asset Hub node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Asset Hub nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/asset-hub/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/asset-hub/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/asset-hub/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/asset-hub/rpc_methods) -- List all available RPC methods

---

## system_properties - Asset Hub RPC Method

# system_properties - Asset Hub RPC Method

Returns the chain-specific properties for Asset Hub, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`system_properties` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Asset Hub
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/asset-hub/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/asset-hub/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/asset-hub/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/asset-hub/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/asset-hub/rpc_methods) -- List all available RPC methods

---

## system_version - Asset Hub RPC Method

# system_version - Asset Hub RPC Method

Returns the node implementation version string on Asset Hub. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Asset Hub?** Build on Polkadot's system parachain managing $4.5B+ in DOT tokens, native USDC/USDT, and NFTs with 50-90% lower fees than Relay Chain, fee payment in any supported asset, 1.5M+ accounts migrated, and trustless Ethereum bridge access.

## When to Use This Method

`system_version` is essential for asset issuers, stablecoin integrators, and teams requiring low-cost token management on Polkadot:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Asset Hub
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for native stablecoin transfers (USDC, USDT), DOT staking and governance, and cross-chain asset management via XCM
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://asset-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://asset-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Asset Hub node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://asset-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Asset Hub node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://asset-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Asset Hub node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://asset-hub-polkadot-rpc.n.dwellir.com')
version = substrate.rpc_request('system_version', [])['result']
print(f'Asset Hub node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://asset-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Asset Hub node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Asset Hub nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/asset-hub/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/asset-hub/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/asset-hub/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/asset-hub/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/asset-hub/rpc_methods) -- List all available RPC methods

---

## Astar RPC Guide

# Astar RPC Guide

## Astar RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Astar supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Astar?

### Multichain smart-contract hub

- Dual EVM + WASM runtimes let teams deploy Solidity and ink! contracts side by side while inheriting Polkadot relay-chain security ([Astar build docs](https://docs.astar.network/docs/build)).
- Build2Earn dApp staking shares block rewards with developers who attract stakers, turning usage into sustainable funding ([Astar dApp staking guide](https://docs.astar.network/docs/learn/dapp-staking/)).

### Optimized for Polkadot 2.0

- Astar adopted Agile Coretime so parachain capacity scales with demand instead of multi-year lease slots, reducing operating costs for long-lived apps ([Polkadot Ecosystem update, Aug 13 2025](https://polkadotecosystem.com/pt/dapps/smart-contracts/astar-network/)).
- Asynchronous Backing on mainnet brings \~6-second block production with larger block weight limits for latency-sensitive DeFi and gaming flows.

### ‍ Enterprise-ready infrastructure

- Dwellir, Chainstack, and other managed providers expose archive-grade RPC endpoints so teams can launch without running collators on day one ([Dwellir Astar network page](https://www.dwellir.com/networks/astar), [Chainstack support announcement](https://chainstack.com/chainstack-introduces-support-for-astar/)).

## Quick Start with Astar

Connect to Astar, Shibuya testnet, or Shiden canary through Dwellir-managed endpoints.

Sign up with [Dwellir](https://dashboard.dwellir.com/register) or your preferred infrastructure partner to replace `YOUR_API_KEY` before sending requests.

### Installation & Setup

cURL
JavaScript (polkadot.js)
Rust (subxt)
Python (py-substrate-interface)

```bash
curl https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "chain_getHeader",
    "params": []
  }'
```

**Sample response (2025-10-03 10:13 UTC):**

```json
{
  "jsonrpc": "2.0",
  "result": {
    "number": "0x9fbc28",
    "parentHash": "0x3f484429ad05365b32f643a9e825794961c1e6f92cde48a2c73935d7773dd5e1",
    "stateRoot": "0x1b983c37356b175bcf38dc1afcc8e31fa893e561f605fcad473697a68ac92169",
    "extrinsicsRoot": "0x783e75691edc604a3f13e1b5c558dd3ca5870ac07ce799c781713219a4a56224",
    "digest": {
      "logs": [
        "0x066175726120159b7a1100000000",
        "0x0452505352902bb51614ab3779fc4f4892aa8e21582a05a3162aef145209312f48c3b37fc7909618af06",
        "0x0466726f6e88015cd52a32691b3d44a3cef762382d728668dbee8c4509c697efe25708d5e6ffd400",
        "0x05617572610101809dd98345fce7c411d130f73a50b2e37d73efe027964dd63ce064275257cc1afb3192c7885ec1813c89350463bce9cd8b4f183b6e8cd779643ff4c476795e83"
      ]
    }
  },
  "id": 1
}
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function main() {
  const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });

  const [chain, nodeName, nodeVersion, runtime] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.state.getRuntimeVersion()
  ]);

  console.log(`Connected to ${chain.toString()} via ${nodeName} ${nodeVersion}`);
  console.log(`specVersion=${runtime.specVersion.toString()}, transactionVersion=${runtime.transactionVersion}`);

  const header = await api.rpc.chain.getHeader();
  console.log(`Latest block #${header.number} (${header.hash.toHex()})`);

  await api.disconnect();
}

main().catch(console.error);
```

```rust
use subxt::{config::substrate::SubstrateConfig, OnlineClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<SubstrateConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let block_hash = api.rpc().finalized_head().await?;
    let header = api.rpc().header(Some(block_hash)).await?.expect("header");

    println!("Finalized block #{:?}", header.number);
    println!("State root {:?}", header.state_root);
    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

api = SubstrateInterface(
    url="wss://api-astar.n.dwellir.com/YOUR_API_KEY",
    ss58_format=5,
    type_registry_preset="substrate-node-template"
)

runtime = api.get_runtime_version()
print("specVersion", runtime['specVersion'], "transactionVersion", runtime['transactionVersion'])

account = api.query(
    module='System',
    storage_function='Account',
    params=['ZEyDXf6563rc78ibEtYQAkHTSKLzMES1m2BrPNdLcma57Tg']
)
print("Free balance", account.value['data']['free'])
```

## Network Information

| Parameter            | Astar Mainnet                                                        | Shiden Canary      | Shibuya Testnet       |
| -------------------- | -------------------------------------------------------------------- | ------------------ | --------------------- |
| Relay chain          | Polkadot                                                             | Kusama             | Tokyo (Astar-managed) |
| Parachain ID         | 2006                                                                 | 2007               | 1000                  |
| Genesis hash         | `0x9eb76c5184c4ab8679d2d5d819fdf90b9c001403e9e17da2e14b6d8aec4029c6` |                    |                       |
| Runtime (2025-10-03) | specVersion `1700`, transactionVersion `3`                           | specVersion `1700` | specVersion `1700`    |
| Unit symbol          | ASTR                                                                 | SDN                | SBY                   |
| Decimals             | 18                                                                   | 18                 | 18                    |
| SS58 prefix          | 5                                                                    | 5                  | 5                     |
| Explorer             | astar.subscan.io                                                     | shiden.subscan.io  | shibuya.subscan.io    |

### Notes

| Parameter                 | Value                                                                                                                           | Details                                                                   |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| Genesis Hash Verification | Recorded via `chain_getBlockHash(0)` on 2025-10-03                                                                              |                                                                           |
| Canary & Testnet Role     | Shiden (Kusama canary) and Shibuya (public testnet) provide staging environments for runtime upgrades before they reach mainnet | [Astar network overview](https://docs.astar.network/docs/learn/networks/) |

## API Reference

Astar exposes the full Substrate RPC surface for block data, storage, extrinsics, and fee estimation, with Frontier also enabling Ethereum-compatible `eth_*`, `net_*`, and `web3_*` endpoints for EVM tooling.

## Common Integration Patterns

### Subscribe to new heads for live indexing

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`Astar block #${header.number.toString()} => ${header.hash.toHex()}`);
});
```

### Fetch native balances via raw storage key

```bash
# System.Account for 5-digit treasury account
curl https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e3a5c81a65b0e6ba8e72e48e58704482922ee694ea772dc63a575845fa57a0c5ea93dfdc2a93ec631d9e426962f1e311"
    ],
    "id": 42
  }'
```

Decode the SCALE-encoded result with polkadot.js or `py-substrate-interface` to access `data.free`, `data.reserved`, and staking locks.

### Pre-flight fees before submitting extrinsics

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

const api = await ApiPromise.create({ provider: new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY') });
const tx = api.tx.balances.transferKeepAlive(
  '5DAAnrj7VHTz5xy1mJQp7vR8J33ePZ8WqWnVfHfV9bPp7PPV',
  1_000_000_000_000
);
const info = await api.rpc.payment.queryInfo(tx.toHex());
console.log(info.toHuman());
```

## Performance Best Practices

- Prefer WebSocket connections for subscriptions and batched queries; fall back to HTTPS for stateless workloads.
- Cache runtime metadata keyed by the latest `specVersion` to avoid re-fetching on every request.
- Use `state_getKeysPaged` or `state_getStoragePaged` with bounded page sizes when crawling large maps such as staking ledgers.
- Track upgrade announcements on the [Astar forum](https://forum.astar.network/) and rehearse changes on Shiden before promoting them to mainnet.
- Implement exponential backoff around `author_submitExtrinsic`; Frontier queues may temporarily reject payloads when Ethereum traffic spikes.

## Troubleshooting

| Symptom                                 | Likely Cause                                  | Resolution                                                                                                             |
| --------------------------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `API key does not exist` errors         | Misconfigured Dwellir endpoint or expired key | Re-issue the key via the [Dwellir dashboard](https://dashboard.dwellir.com/register) and update environment variables. |
| WebSocket disconnects on idle workloads | Provider closes idle connections              | Enable heartbeat pings or reconnect logic every 30 seconds.                                                            |

## Smoke Tests

Run these checks before promoting to production:

1. **system\_health:** Expect `isSyncing: false` and peer count > 8.
2. **chain\_getHeader:** Confirm block numbers advance every \~6 seconds.
3. **state\_getStorage(System.Account):** Verify SCALE decoding of balances for a known treasury or team account.
4. **payment\_queryInfo on a signed extrinsic:** Validate the fee model before broadcasting from CI/CD.

## Resources & Tools

- [Astar Documentation](https://docs.astar.network/): network architecture, node operations, and dApp staking guides.
- [Astar GitHub Releases](https://github.com/AstarNetwork/Astar/releases): runtime and client binaries.
- [Dwellir Astar Network Page](https://www.dwellir.com/networks/astar): managed endpoints and quick-start snippets.
- [Astar Subscan Explorer](https://astar.subscan.io): block, extrinsic, and account analytics for monitoring deployments.

Ready to deploy? Spin up a staging environment on Shibuya, soak test on Shiden, then cut over to Astar mainnet with confidence.

---

## author_pendingExtrinsics - Astar RPC Method

# author_pendingExtrinsics - Astar RPC Method

Returns all pending extrinsics currently in the transaction pool on Astar. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`author_pendingExtrinsics` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Astar
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Astar transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/astar/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/astar/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/astar/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Astar RPC Method

# author_rotateKeys - Astar RPC Method

Generate a new set of session keys on Astar. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`author_rotateKeys` is critical for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Validator Setup** - Generate initial session keys when setting up a new validator on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Astar:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/astar/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/astar/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Astar RPC Method

# author_submitAndWatchExtrinsic - Astar RPC Method

Submits a signed extrinsic to Astar and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Astar
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

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

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-astar.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-astar.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-astar.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-astar.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/astar/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/astar/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/astar/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/astar/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Astar RPC Method

# author_submitExtrinsic - Astar RPC Method

Submits a fully signed extrinsic to Astar for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`author_submitExtrinsic` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Token Transfers** -- Send native tokens or assets between accounts on Astar
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

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

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-astar.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/astar/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/astar/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Astar RPC Method

# beefy_getFinalizedHead - Astar RPC Method

Returns the block hash of the latest BEEFY-finalized block on Astar. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`beefy_getFinalizedHead` is important for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

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

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/astar/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/astar/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/astar/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Astar RPC Method

# chain_getBlock - Astar RPC Method

Retrieves complete block information from Astar, including the block header, extrinsics, and justifications.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/astar/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/astar/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/astar/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Astar RPC Method

# chain_getBlockHash - Astar RPC Method

Returns the block hash for a given block number on Astar. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`chain_getBlockHash` is fundamental for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Astar
- **Block Navigation** - Navigate the blockchain history for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Astar
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Astar for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Astar state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Astar network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/astar/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/astar/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Astar RPC Method

# chain_getFinalizedHead - Astar RPC Method

Returns the hash of the last finalized block on Astar. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`chain_getFinalizedHead` is critical for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Astar
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-astar.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Astar:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/astar/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/astar/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/astar/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Astar RPC Method

# chain_getHeader - Astar RPC Method

Returns the block header for a given hash on Astar. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`chain_getHeader` is ideal for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Astar
- **Chain Synchronization** - Track block production and monitor chain progress for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Astar:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Astar chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Astar block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/astar/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/astar/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/astar/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Astar RPC Method

# chain_subscribeFinalizedHeads - Astar RPC Method

Subscribe to receive notifications when blocks are finalized on Astar. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Exchange Deposits** - Only credit funds after finalization for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-astar.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-astar.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-astar.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Astar:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/astar/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/astar/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/astar/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Astar RPC Method

# chain_subscribeNewHeads - Astar RPC Method

Subscribe to receive notifications when new block headers are produced on Astar. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`chain_subscribeNewHeads` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Block Monitoring** - Track new blocks in real time on Astar for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-astar.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-astar.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-astar.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Astar as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Astar:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/astar/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/astar/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/astar/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## eth_accounts - Astar RPC Method

# eth_accounts - Astar RPC Method

Returns a list of addresses owned by the client on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

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

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/astar/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/astar/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Astar RPC Method

# eth_blockNumber - Astar RPC Method

Returns the number of the most recent block on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_blockNumber` is fundamental for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Syncing Applications** - Keep your dApp in sync with the latest Astar blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Astar block:', blockNumber);

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Astar block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Astar block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
print(f'Astar block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Astar block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Astar:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Astar:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Astar node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/astar/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/astar/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/astar/eth_syncing) - Check if node is still syncing

---

## eth_call - Astar RPC Method

# eth_call - Astar RPC Method

Executes a new message call immediately without creating a transaction on Astar. Used for reading smart contract state.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

The `eth_call` method serves these key scenarios for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Astar
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const walletAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Astar. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Astar
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Astar

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    data := common.FromHex("0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/astar/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Astar RPC Method

# eth_chainId - Astar RPC Method

Returns the chain ID used for transaction signing on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_chainId` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/astar/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/astar/eth_syncing) - Check sync status

---

## eth_coinbase - Astar RPC Method

# eth_coinbase - Astar RPC Method

Checks the legacy `eth_coinbase` compatibility method on Astar. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Astar coinbase:', result);
}

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Astar coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Astar coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Astar coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Astar coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Astar nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/astar/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/astar/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/astar/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Astar RPC Method

# eth_estimateGas - Astar RPC Method

Estimates the gas necessary to execute a transaction on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Astar
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Astar.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

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

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Astar may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 0.1)
```

```go
package main

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

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

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

    toAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/astar/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Astar RPC Method

# eth_feeHistory - Astar RPC Method

Returns historical gas fee data on Astar, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Astar without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Astar.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Astar) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

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

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

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

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/astar/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/astar/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/astar/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/astar/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Astar RPC Method

# eth_gasPrice - Astar RPC Method

Returns the current gas price on Astar in wei.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Astar
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Astar. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Astar, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Astar: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Astar supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

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

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

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

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/astar/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/astar/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/astar/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Astar RPC Method

# eth_getBalance - Astar RPC Method

Returns the balance of a given address on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getBalance` is fundamental for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Astar
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Astar
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

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

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Astar. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Astar`);
  return balance;
}

displayBalance('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Astar at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Astar')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Astar')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Astar.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-astar.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-astar.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/astar/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/astar/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Astar RPC Method

# eth_getBlockByHash - Astar RPC Method

Returns information about a block by hash on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getBlockByHash` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Astar
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Astar.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Astar.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-astar.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const blockHash = '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockHash := common.HexToHash("0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/astar/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Astar RPC Method

# eth_getBlockByNumber - Astar RPC Method

Returns information about a block by block number on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getBlockByNumber` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Astar
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Astar with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Astar. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-astar.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

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

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

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

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/astar/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/astar/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Astar RPC Method

# eth_getBlockReceipts - Astar RPC Method

Returns all transaction receipts for a block on Astar. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getBlockReceipts` is useful for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Astar, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Astar. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-astar.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/astar/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/astar/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/astar/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Astar RPC Method

# eth_getCode - Astar RPC Method

Returns the bytecode at a given address on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getCode` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Astar
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Astar:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Astar:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/astar/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/astar/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Astar RPC Method

# eth_getFilterChanges - Astar RPC Method

Polls a filter on Astar for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getFilterChanges` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Astar
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

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

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

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

    // Create a log filter
    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Astar:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/astar/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/astar/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/astar/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/astar/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/astar/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Astar RPC Method

# eth_getFilterLogs - Astar RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Astar. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getFilterLogs` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Astar
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/astar/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/astar/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/astar/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/astar/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Astar RPC Method

# eth_getLogs - Astar RPC Method

Returns an array of all logs matching a given filter object on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Astar for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Astar
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Astar.

```javascript
const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Astar enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Astar, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/astar/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/astar/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Astar RPC Method

# eth_getStorageAt - Astar RPC Method

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

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getStorageAt` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **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 cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **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": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "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-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '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-astar.n.dwellir.com/YOUR_API_KEY');
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

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-astar.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 = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
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-astar.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-astar.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    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 Astar:

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

const provider = new JsonRpcProvider('https://api-astar.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-astar.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 = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
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 Astar:`);
  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/astar/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/astar/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/astar/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/astar/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Astar RPC Method

# eth_getTransactionByHash - Astar RPC Method

Returns the information about a transaction by transaction hash on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getTransactionByHash` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Astar
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Astar. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Astar. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-astar.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const txHash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/astar/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Astar RPC Method

# eth_getTransactionCount - Astar RPC Method

Returns the number of transactions sent from an address on Astar, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getTransactionCount` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Astar
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

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

## 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-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Astar nonce:', nonce);

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

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

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
nonce = get_transaction_count(address)
print(f'Astar nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Astar nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Astar:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/astar/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/astar/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/astar/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Astar RPC Method

# eth_getTransactionReceipt - Astar RPC Method

Returns the receipt of a transaction by transaction hash on Astar. Receipt is only available for mined transactions.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_getTransactionReceipt` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Astar and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Astar. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Astar, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-astar.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/astar/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/astar/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Astar RPC Method

# eth_hashrate - Astar RPC Method

Returns the legacy `eth_hashrate` compatibility value on Astar. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Astar hashrate:', parseInt(payload.result, 16), 'H/s');
}

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Astar hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Astar hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Astar hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Astar hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/astar/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/astar/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Astar RPC Method

# eth_maxPriorityFeePerGas - Astar RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Astar. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Astar
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Astar priority fee:', priorityFeeGwei, 'Gwei');

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Astar priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

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

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

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

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Astar priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Astar:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Astar:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/astar/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/astar/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/astar/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/astar/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Astar RPC Method

# eth_mining - Astar RPC Method

Checks the legacy `eth_mining` compatibility method on Astar. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Astar mining:', payload.result);
}

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Astar mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Astar mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Astar mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Astar mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/astar/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/astar/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Astar RPC Method

# eth_newBlockFilter - Astar RPC Method

Creates a filter on Astar that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_newBlockFilter` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Block Monitoring** - Detect new blocks on Astar as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

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

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

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Astar:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/astar/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/astar/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/astar/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Astar RPC Method

# eth_newFilter - Astar RPC Method

Creates a filter object on Astar based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_newFilter` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Event Monitoring** - Subscribe to specific contract events on Astar such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Astar:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/astar/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/astar/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/astar/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/astar/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/astar/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Astar RPC Method

# eth_newPendingTransactionFilter - Astar RPC Method

Creates a filter on Astar that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Mempool Monitoring** - Observe unconfirmed transactions on Astar to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Astar...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Astar:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/astar/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/astar/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/astar/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Astar RPC Method

# eth_protocolVersion - Astar RPC Method

Returns the current Ethereum protocol version used by the Astar node.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_protocolVersion` is useful for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Astar protocol version:', version);

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

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Astar protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Astar protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
print(f'Astar protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Astar protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Astar nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/astar/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/astar/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/astar/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Astar RPC Method

# eth_sendRawTransaction - Astar RPC Method

Submits a pre-signed transaction for broadcast to Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Astar
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Astar mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-astar.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/astar/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/astar/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/astar/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/astar/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Astar RPC Method

# eth_sendTransaction - Astar RPC Method

Creates and sends a new transaction from an unlocked account on Astar. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Astar tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Astar tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Astar tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Astar tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Astar tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Astar dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/astar/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/astar/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Astar RPC Method

# eth_signTransaction - Astar RPC Method

Signs a transaction with the private key of the specified account on Astar without submitting it to the network.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Astar tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Astar tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Astar tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Astar:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/astar/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/astar/eth_accounts) - List accounts available for signing

---

## eth_syncing - Astar RPC Method

# eth_syncing - Astar RPC Method

Returns the sync status of your Astar node - either `false` when fully synced, or an object describing the sync progress.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_syncing` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Astar node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Astar node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Astar node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/astar/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/astar/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/astar/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Astar RPC Method

# eth_uninstallFilter - Astar RPC Method

Removes a filter on Astar that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`eth_uninstallFilter` is important for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/astar/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/astar/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/astar/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/astar/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/astar/eth_getFilterLogs) - Get all logs matching a filter

---

## grandpa_roundState - Astar RPC Method

# grandpa_roundState - Astar RPC Method

Returns the state of the current GRANDPA finality round on Astar when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`grandpa_roundState` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Astar, critical for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/astar/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/astar/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/astar/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/astar/system_health) -- Check overall node health including sync and peer status

---

## net_listening - Astar RPC Method

# net_listening - Astar RPC Method

Checks whether the connected Astar client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`net_listening` is useful for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

try {
  const listening = await provider.send('net_listening', []);
  console.log('Astar node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Astar node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Astar node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/astar/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/astar/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/astar/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/astar/web3_clientVersion) - Get node client info

---

## net_peerCount - Astar RPC Method

# net_peerCount - Astar RPC Method

Returns the number of peers currently connected to your Astar node.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`net_peerCount` is important for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Astar deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Astar peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Astar peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Astar peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Astar nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/astar/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/astar/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/astar/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/astar/web3_clientVersion) - Get node client info

---

## net_version - Astar RPC Method

# net_version - Astar RPC Method

Returns the current network ID on Astar as a decimal string. The network ID identifies which network the node is connected to.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`net_version` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Endpoint Identification** - Confirm your application is connected to the expected Astar network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const networkId = await provider.send('net_version', []);
console.log('Astar network ID:', networkId);

// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Astar network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Astar network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/astar/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/astar/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/astar/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/astar/eth_syncing) - Check node sync progress

---

## payment_queryFeeDetails - Astar RPC Method

# payment_queryFeeDetails - Astar RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Astar. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`payment_queryFeeDetails` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Astar
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/astar/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/astar/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/astar/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/astar/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Astar RPC Method

# payment_queryInfo - Astar RPC Method

Estimates the fee for an encoded extrinsic on Astar. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`payment_queryInfo` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Astar
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/astar/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/astar/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/astar/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/astar/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Astar RPC Method

# rpc_methods - Astar RPC Method

Returns a list of all RPC methods exposed by the Astar node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`rpc_methods` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Astar node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Astar endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-astar.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Astar endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/astar/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/astar/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/astar/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Astar RPC Method

# state_call - Astar RPC Method

Calls a runtime API function on Astar and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`state_call` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/astar/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/astar/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/astar/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/astar/system_version) -- Get the node version for compatibility checking

---

## state_getKeys

# state_getKeys

## Description

Returns storage keys with a given prefix. Because Astar staking maps can be large, use this method sparingly and follow with `state_getKeysPaged` for controlled pagination.

## Parameters

| Position       | Type   | Description                                  |
| -------------- | ------ | -------------------------------------------- |
| 0              | string | Storage key prefix in hex                    |
| 1 *(optional)* | string | Block hash                                   |
| 2 *(optional)* | number | Result limit (ignored on some node versions) |

## Request Example

Get collator session keys by prefixing `Session.NextKeys` (no account parameter).

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3",
    null,
    5
  ],
  "id": 7
}
```

## Response Example

```json
{
  "jsonrpc": "2.0",
  "id": 7,
  "result": [
    "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb30165c612f75544f29a2b2224d8a6944df8f70196c856ae141ecf1aeb3de10d54461317f2fdeae21b",
    "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb302a1a4c9e333badf063b6446a3e6b0781d73ea137f9c74f59918312cb7938a1f234287ea08418633",
    "…"
  ]
}
```

If a node returns `Response is too big`, switch to `state_getKeysPaged` with smaller page sizes.

## Code Examples

Python
JavaScript

```python
substrate = SubstrateInterface(url="wss://api-astar.n.dwellir.com/YOUR_API_KEY", ss58_format=5)
prefix = substrate.generate_storage_hash('Session', 'NextKeys')
keys = substrate.rpc_request('state_getKeys', [prefix, None, 5])['result']
print(keys[:3])
```

```typescript
const prefix = api.query.session.nextKeys.keyPrefix();
const keys = await api.rpc.state.getKeys(prefix.toHex());
console.log(`Returned ${keys.length} keys`);
```

---

## state_getKeysPaged - Astar RPC Method

# state_getKeysPaged - Astar RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Astar. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`state_getKeysPaged` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Astar
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-astar.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/astar/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/astar/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Astar RPC Method

# state_getMetadata - Astar RPC Method

Returns the runtime metadata for Astar as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`state_getMetadata` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Astar
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Astar:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Astar:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/astar/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/astar/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Astar RPC Method

# state_getRuntimeVersion - Astar RPC Method

Returns the runtime version information for Astar, including the spec name, spec version, implementation version, and supported API versions.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`state_getRuntimeVersion` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Astar
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Astar in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/astar/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/astar/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Astar RPC Method

# state_getStorage - Astar RPC Method

Returns the SCALE-encoded storage value for a given key on Astar. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`state_getStorage` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Astar
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/astar/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/astar/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Astar RPC Method

# state_queryStorageAt - Astar RPC Method

Queries multiple storage keys at a specific block on Astar, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`state_queryStorageAt` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Astar
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/astar/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/astar/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/astar/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/astar/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Astar RPC Method

# system_chain - Astar RPC Method

Returns the chain name of the Astar network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`system_chain` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Network Verification** -- Confirm your application is connected to the correct Astar network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-astar.n.dwellir.com/YOUR_API_KEY', 'Astar');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/astar/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/astar/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/astar/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/astar/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/astar/rpc_methods) -- List all available RPC methods

---

## system_health - Astar RPC Method

# system_health - Astar RPC Method

Returns the health status of the Astar node, including peer count, sync state, and whether the node expects to have peers.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`system_health` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Astar
- **Load Balancing** - Route requests only to healthy, fully synced nodes for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-astar.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-astar.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Astar:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Astar nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-astar.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/astar/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/astar/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Astar RPC Method

# system_name - Astar RPC Method

Returns the node implementation name on Astar. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`system_name` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Astar
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Astar node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Astar node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Astar node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Astar node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Astar node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Astar nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/astar/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/astar/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/astar/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/astar/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/astar/rpc_methods) -- List all available RPC methods

---

## system_properties - Astar RPC Method

# system_properties - Astar RPC Method

Returns the chain-specific properties for Astar, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`system_properties` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Astar
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/astar/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/astar/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/astar/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/astar/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/astar/rpc_methods) -- List all available RPC methods

---

## system_version - Astar RPC Method

# system_version - Astar RPC Method

Returns the node implementation version string on Astar. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`system_version` is essential for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Astar
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for cross-chain DeFi, multi-VM smart contracts, and XCM-enabled interoperability with Ethereum and Cosmos
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-astar.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Astar node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Astar node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-astar.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Astar node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-astar.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Astar node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-astar.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Astar node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Astar nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/astar/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/astar/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/astar/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/astar/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/astar/rpc_methods) -- List all available RPC methods

---

## txpool_content - Astar RPC Method

# txpool_content - Astar RPC Method

Returns the full pending and queued transaction pool for the connected Astar endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`txpool_content` is useful for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/astar/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/astar/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/astar/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Astar RPC Method

# txpool_status - Astar RPC Method

Returns transaction pool counters for the connected Astar endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`txpool_status` is valuable for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/astar/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/astar/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/astar/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Astar RPC Method

# web3_clientVersion - Astar RPC Method

Returns the current client software version string for your Astar node, including the client name, version number, OS, and runtime.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

## When to Use This Method

`web3_clientVersion` is valuable for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Astar client:', clientVersion);

// Using fetch
const response = await fetch('https://api-astar.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Astar client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Astar client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/astar/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/astar/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/astar/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/astar/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Astar RPC Method

# web3_sha3 - Astar RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Astar.

> **Why Astar?** Build on Polkadot's leading dApp hub supporting EVM, WASM, and upcoming PolkaVM environments with EVM + WASM + PolkaVM support, Build2Earn developer rewards, dApp Staking, and Soneium cross-layer integration.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for multi-chain dApp developers, DeFi builders, and teams leveraging Polkadot + Ethereum ecosystems:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-astar.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

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

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

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-astar.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

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

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-astar.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/astar/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/astar/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/astar/web3_clientVersion) - Get node client version

---

## Avalanche - High-Performance Blockchain Platform

# Avalanche - High-Performance Blockchain Platform

## Avalanche RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Avalanche supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Avalanche?

Avalanche is a high-performance blockchain platform that delivers sub-second finality and supports custom blockchain networks. Built on the innovative Avalanche consensus mechanism, it offers:

### **Lightning Fast Performance**

- **Sub-second finality** - Transactions confirm in under 1 second
- **4,500+ TPS** - Industry-leading throughput capacity
- **Low fees** - Cost-effective transactions with predictable pricing

### **Unique Three-Chain Architecture**

- **X-Chain** - Exchange Chain for asset creation and trading
- **P-Chain** - Platform Chain for validator coordination and subnets
- **C-Chain** - Contract Chain for Ethereum-compatible smart contracts

### **Enterprise Security**

- **Avalanche Consensus** - Novel consensus protocol with strong safety guarantees
- **Validator Network** - Decentralized network of validators securing the platform
- **Battle-tested** - Processing millions of transactions since mainnet launch

### **Thriving Ecosystem**

- **400+ projects** - Growing DeFi, Gaming, and NFT ecosystem
- **EVM Compatible** - Full Ethereum compatibility on C-Chain
- **Subnet Support** - Create custom blockchain networks

## Quick Start with Avalanche C-Chain

Connect to Avalanche C-Chain in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Avalanche C-Chain mainnet
const provider = new JsonRpcProvider(
  'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Avalanche C-Chain mainnet
const web3 = new Web3(
  'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Avalanche:', chainId === 43114);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { avalanche } from 'viem/chains';

// Create Avalanche client
const client = createPublicClient({
  chain: avalanche,
  transport: http('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 43114     | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | AVAX      | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Avalanche C-Chain supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with sub-second finality and high throughput.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Avalanche specific: Fast finality means quick confirmations
  console.log('Transaction confirmed in block:', receipt.blockNumber);

  return receipt;
}
```

### Fast Finality Optimization

Leverage Avalanche's sub-second finality:

```javascript
// Avalanche transactions finalize quickly
async function fastConfirmation(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // On Avalanche, 1 confirmation is typically sufficient
  if (receipt.blockNumber) {
    console.log('Transaction finalized with 1 confirmation');
    return receipt;
  }
}
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with optimal batch size for Avalanche
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 5000; // Avalanche recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class AvalancheProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Gas required exceeds allowance"

Avalanche uses dynamic gas pricing. Always estimate gas properly:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: await provider.estimateGas({
    to: recipient,
    value: amount
  })
};
```

### Error: "Transaction underpriced"

Avalanche uses EIP-1559 pricing. Use dynamic gas pricing:

```javascript
// Get current network conditions
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Avalanche C-Chain is seamless:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Avalanche)
const provider = new JsonRpcProvider(
  'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'
);

// Smart contracts work identically
// Same tooling and libraries
// Native token is AVAX instead of ETH
// Note: Different chain ID (43114)
// Note: Much faster finality (~1 second)
```

### From Other EVM Chains

Avalanche C-Chain is fully EVM compatible:

```javascript
// Same contract deployment process
const contractFactory = new ContractFactory(abi, bytecode, signer);
const contract = await contractFactory.deploy(...constructorArgs);

// Wait for deployment (much faster on Avalanche)
await contract.waitForDeployment();
```

## Resources & Tools

### Official Resources

- [Avalanche Documentation](https://docs.avax.network)
- [Avalanche Explorer](https://snowtrace.io)
- [Avalanche Bridge](https://bridge.avax.network)

### Developer Tools

- [Hardhat Config](https://build.avax.network/docs/dapps/toolchains/hardhat)
- [Foundry Setup](https://build.avax.network/docs/dapps/toolchains/foundry)
- [Core Wallet](https://core.app)

### Ecosystem

- [DeFi Llama](https://defillama.com/chain/Avalanche) - Track Avalanche DeFi
- [Avalanche Website](https://www.avax.network/) - Discover projects and ecosystem
- [Subnets](https://subnets.avax.network) - Custom blockchain networks

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Best Avalanche RPC Providers 2026](https://www.dwellir.com/blog/top-avalanche-rpc-providers)

***

*Start building on Avalanche with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Avalanche RPC Method

# debug_traceBlock - Avalanche RPC Method

Traces all transactions in a block on Avalanche by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Avalanche - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Avalanche
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Avalanche:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Avalanche blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/avalanche/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/avalanche/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Avalanche RPC Method

# debug_traceBlockByHash - Avalanche RPC Method

Traces all transactions in a block on Avalanche identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Avalanche - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Avalanche
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const blockHash = '0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Avalanche:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Avalanche:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/avalanche/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/avalanche/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/avalanche/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/avalanche/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Avalanche RPC Method

# debug_traceBlockByNumber - Avalanche RPC Method

Traces all transactions in a block on Avalanche identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Avalanche - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Avalanche execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Avalanche:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Avalanche:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/avalanche/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/avalanche/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/avalanche/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Avalanche RPC Method

# debug_traceCall - Avalanche RPC Method

Traces a call on Avalanche without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Avalanche - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Avalanche
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "data": "0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
        "data": "0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
        "data": "0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    data: '0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    data: '0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    'data': '0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
        "data": "0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Avalanche to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Avalanche:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Avalanche:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/avalanche/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/avalanche/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Avalanche RPC Method

# debug_traceTransaction - Avalanche RPC Method

Traces a transaction execution on Avalanche by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Avalanche
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const txHash = '0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

tx_hash = '0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/avalanche/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/avalanche/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Avalanche RPC Method

# eth_accounts - Avalanche RPC Method

Returns a list of addresses owned by the client on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for enterprise developers, RWA tokenizers, and teams building custom blockchain networks in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

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

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/avalanche/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/avalanche/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Avalanche RPC Method

# eth_blockNumber - Avalanche RPC Method

Returns the number of the most recent block on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_blockNumber` is fundamental for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Syncing Applications** - Keep your dApp in sync with the latest Avalanche blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Avalanche block:', blockNumber);

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const blockNumber = await provider.getBlockNumber();
console.log('Avalanche block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Avalanche block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
print(f'Avalanche block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Avalanche block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Avalanche:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Avalanche:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Avalanche node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/avalanche/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/avalanche/eth_syncing) - Check if node is still syncing

---

## eth_call - Avalanche RPC Method

# eth_call - Avalanche RPC Method

Executes a new message call immediately without creating a transaction on Avalanche. Used for reading smart contract state.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

The `eth_call` method serves these key scenarios for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Avalanche
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const tokenAddress = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';
const walletAddress = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Avalanche. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const routerAddress = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Avalanche
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Avalanche

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "data": "0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "data": "0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    contractAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    data := common.FromHex("0x70a0823100000000000000000000000009383137c1eee3e1a8bc781228e4199f6b4a9bbf")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Avalanche RPC Method

# eth_chainId - Avalanche RPC Method

Returns the chain ID used for transaction signing on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_chainId` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/avalanche/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/avalanche/eth_syncing) - Check sync status

---

## eth_coinbase - Avalanche RPC Method

# eth_coinbase - Avalanche RPC Method

Checks the legacy `eth_coinbase` compatibility method on Avalanche. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for enterprise developers, RWA tokenizers, and teams building custom blockchain networks when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Avalanche coinbase:', result);
}

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Avalanche coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Avalanche coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
try:
    print(f'Avalanche coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Avalanche coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Avalanche nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/avalanche/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/avalanche/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/avalanche/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Avalanche RPC Method

# eth_estimateGas - Avalanche RPC Method

Estimates the gas necessary to execute a transaction on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Avalanche
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Avalanche.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Avalanche may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "to": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf', 0.1)
```

```go
package main

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

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

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

    toAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/avalanche/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Avalanche RPC Method

# eth_feeHistory - Avalanche RPC Method

Returns historical gas fee data on Avalanche, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Avalanche without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Avalanche.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Avalanche) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

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

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

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

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/avalanche/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/avalanche/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Avalanche RPC Method

# eth_gasPrice - Avalanche RPC Method

Returns the current gas price on Avalanche in wei.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Avalanche
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Avalanche. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Avalanche, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Avalanche: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Avalanche supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

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

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

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

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/avalanche/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/avalanche/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Avalanche RPC Method

# eth_getBalance - Avalanche RPC Method

Returns the balance of a given address on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getBalance` is fundamental for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Avalanche
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Avalanche
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

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

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Avalanche. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Avalanche`);
  return balance;
}

displayBalance('0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Avalanche at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Avalanche')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Avalanche')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Avalanche.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")

    address := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/avalanche/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/avalanche/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Avalanche RPC Method

# eth_getBlockByHash - Avalanche RPC Method

Returns information about a block by hash on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getBlockByHash` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Avalanche
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the fastest smart contract platform with sub-second finality and customizable L1 subnets
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Avalanche.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the fastest smart contract platform with sub-second finality and customizable L1 subnets.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Avalanche.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")

    knownHash := common.HexToHash("0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const blockHash = '0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

block_hash = '0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockHash := common.HexToHash("0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/avalanche/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Avalanche RPC Method

# eth_getBlockByNumber - Avalanche RPC Method

Returns information about a block by block number on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getBlockByNumber` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Avalanche
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the fastest smart contract platform with sub-second finality and customizable L1 subnets

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Avalanche with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Avalanche. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the fastest smart contract platform with sub-second finality and customizable L1 subnets expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

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

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

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

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/avalanche/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/avalanche/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/avalanche/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Avalanche RPC Method

# eth_getBlockReceipts - Avalanche RPC Method

Returns all transaction receipts for a block on Avalanche. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getBlockReceipts` is useful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Avalanche, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Avalanche. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the fastest smart contract platform with sub-second finality and customizable L1 subnets, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xb40d80aebafa6c7598ca8bc978354fa1c44f34b08c3f328882b714cb533615bb",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/avalanche/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/avalanche/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Avalanche RPC Method

# eth_getCode - Avalanche RPC Method

Returns the bytecode at a given address on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getCode` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Avalanche
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Avalanche:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Avalanche:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/avalanche/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/avalanche/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Avalanche RPC Method

# eth_getFilterChanges - Avalanche RPC Method

Polls a filter on Avalanche for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getFilterChanges` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Avalanche
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

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

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

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

    // Create a log filter
    contractAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Avalanche:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/avalanche/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/avalanche/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/avalanche/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/avalanche/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/avalanche/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Avalanche RPC Method

# eth_getFilterLogs - Avalanche RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Avalanche. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getFilterLogs` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Avalanche
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/avalanche/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/avalanche/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/avalanche/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/avalanche/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Avalanche RPC Method

# eth_getLogs - Avalanche RPC Method

Returns an array of all logs matching a given filter object on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Avalanche for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Avalanche
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const tokenAddress = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Avalanche.

```javascript
const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Avalanche enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Avalanche, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/avalanche/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/avalanche/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Avalanche RPC Method

# eth_getStorageAt - Avalanche RPC Method

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

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getStorageAt` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **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 institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **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": [
    "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf', '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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';

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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getStorageAt',
            'params': [address, hex(position), block],
            'id': 1
        }
    )
    return response.json()['result']

address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    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 Avalanche:

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

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 = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';
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 Avalanche:`);
  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/avalanche/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/avalanche/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/avalanche/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Avalanche RPC Method

# eth_getTransactionByHash - Avalanche RPC Method

Returns the information about a transaction by transaction hash on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getTransactionByHash` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Avalanche
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the fastest smart contract platform with sub-second finality and customizable L1 subnets

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Avalanche. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Avalanche. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the fastest smart contract platform with sub-second finality and customizable L1 subnets.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")

    txHash := common.HexToHash("0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const txHash = '0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

tx_hash = '0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/avalanche/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Avalanche RPC Method

# eth_getTransactionCount - Avalanche RPC Method

Returns the number of transactions sent from an address on Avalanche, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getTransactionCount` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Avalanche
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

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

## 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-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Avalanche nonce:', nonce);

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf'
nonce = get_transaction_count(address)
print(f'Avalanche nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Avalanche nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Avalanche:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/avalanche/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/avalanche/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/avalanche/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Avalanche RPC Method

# eth_getTransactionReceipt - Avalanche RPC Method

Returns the receipt of a transaction by transaction hash on Avalanche. Receipt is only available for mined transactions.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_getTransactionReceipt` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Avalanche and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the fastest smart contract platform with sub-second finality and customizable L1 subnets by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Avalanche. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Avalanche, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the fastest smart contract platform with sub-second finality and customizable L1 subnets. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")

    txHash := common.HexToHash("0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the fastest smart contract platform with sub-second finality and customizable L1 subnets
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const txHash = '0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

tx_hash = '0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0xfe055919188f8e2360bead9ecd97ffa782c610730e9084c6533f799bafafa7e4")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/avalanche/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/avalanche/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Avalanche RPC Method

# eth_hashrate - Avalanche RPC Method

Returns the legacy `eth_hashrate` compatibility value on Avalanche. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Avalanche hashrate:', parseInt(payload.result, 16), 'H/s');
}

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Avalanche hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Avalanche hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
try:
    print(f'Avalanche hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Avalanche hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/avalanche/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/avalanche/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/avalanche/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Avalanche RPC Method

# eth_maxPriorityFeePerGas - Avalanche RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Avalanche. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Avalanche
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Avalanche priority fee:', priorityFeeGwei, 'Gwei');

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Avalanche priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

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

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

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

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Avalanche priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Avalanche:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Avalanche:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/avalanche/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/avalanche/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/avalanche/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Avalanche RPC Method

# eth_mining - Avalanche RPC Method

Checks the legacy `eth_mining` compatibility method on Avalanche. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Avalanche mining:', payload.result);
}

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Avalanche mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Avalanche mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
try:
    print(f'Avalanche mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Avalanche mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/avalanche/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/avalanche/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/avalanche/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Avalanche RPC Method

# eth_newBlockFilter - Avalanche RPC Method

Creates a filter on Avalanche that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_newBlockFilter` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Block Monitoring** - Detect new blocks on Avalanche as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

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

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

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Avalanche:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/avalanche/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/avalanche/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/avalanche/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/avalanche/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Avalanche RPC Method

# eth_newFilter - Avalanche RPC Method

Creates a filter object on Avalanche based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_newFilter` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Event Monitoring** - Subscribe to specific contract events on Avalanche such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    contractAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Avalanche:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/avalanche/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/avalanche/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/avalanche/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/avalanche/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/avalanche/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Avalanche RPC Method

# eth_newPendingTransactionFilter - Avalanche RPC Method

Creates a filter on Avalanche that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Mempool Monitoring** - Observe unconfirmed transactions on Avalanche to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for institutional RWA tokenization ($18B+ transfer volume), gaming subnets, and enterprise blockchains

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Avalanche...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Avalanche:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/avalanche/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/avalanche/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/avalanche/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Avalanche RPC Method

# eth_protocolVersion - Avalanche RPC Method

Returns the current Ethereum protocol version used by the Avalanche node.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_protocolVersion` is useful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Avalanche protocol version:', version);

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Avalanche protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Avalanche protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
print(f'Avalanche protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Avalanche protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Avalanche nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/avalanche/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/avalanche/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/avalanche/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Avalanche RPC Method

# eth_sendRawTransaction - Avalanche RPC Method

Submits a pre-signed transaction for broadcast to Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Avalanche
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Avalanche mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/avalanche/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x09383137c1eee3e1a8bc781228e4199f6b4a9bbf")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/avalanche/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/avalanche/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Avalanche RPC Method

# eth_sendTransaction - Avalanche RPC Method

Creates and sends a new transaction from an unlocked account on Avalanche. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Avalanche tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Avalanche tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Avalanche tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Avalanche tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Avalanche tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Avalanche dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/avalanche/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/avalanche/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Avalanche RPC Method

# eth_signTransaction - Avalanche RPC Method

Signs a transaction with the private key of the specified account on Avalanche without submitting it to the network.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for enterprise developers, RWA tokenizers, and teams building custom blockchain networks in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Avalanche tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Avalanche tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Avalanche tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Avalanche:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/avalanche/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/avalanche/eth_accounts) - List accounts available for signing

---

## eth_syncing - Avalanche RPC Method

# eth_syncing - Avalanche RPC Method

Returns the sync status of your Avalanche node - either `false` when fully synced, or an object describing the sync progress.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_syncing` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Avalanche node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Avalanche node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Avalanche node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/avalanche/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/avalanche/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/avalanche/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/avalanche/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Avalanche RPC Method

# eth_uninstallFilter - Avalanche RPC Method

Removes a filter on Avalanche that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`eth_uninstallFilter` is important for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/avalanche/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/avalanche/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/avalanche/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/avalanche/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/avalanche/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Avalanche RPC Method

# net_listening - Avalanche RPC Method

Checks whether the connected Avalanche client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`net_listening` is useful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Avalanche node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

try:
    listening = w3.net.listening
    print(f'Avalanche node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Avalanche node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/avalanche/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/avalanche/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/avalanche/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/avalanche/web3_clientVersion) - Get node client info

---

## net_peerCount - Avalanche RPC Method

# net_peerCount - Avalanche RPC Method

Returns the number of peers currently connected to your Avalanche node.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`net_peerCount` is important for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Avalanche deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Avalanche peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

peer_count = w3.net.peer_count
print(f'Avalanche peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Avalanche peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Avalanche nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/avalanche/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/avalanche/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/avalanche/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/avalanche/web3_clientVersion) - Get node client info

---

## net_version - Avalanche RPC Method

# net_version - Avalanche RPC Method

Returns the current network ID on Avalanche as a decimal string. The network ID identifies which network the node is connected to.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`net_version` is essential for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Endpoint Identification** - Confirm your application is connected to the expected Avalanche network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const networkId = await provider.send('net_version', []);
console.log('Avalanche network ID:', networkId);

// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

network_id = w3.net.version
print(f'Avalanche network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Avalanche network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/avalanche/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/avalanche/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/avalanche/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/avalanche/eth_syncing) - Check node sync progress

---

## rpc_modules - Avalanche RPC Method

# rpc_modules - Avalanche RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Avalanche endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`rpc_modules` is useful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/avalanche/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/avalanche/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Avalanche RPC Method

# web3_clientVersion - Avalanche RPC Method

Returns the current client software version string for your Avalanche node, including the client name, version number, OS, and runtime.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

## When to Use This Method

`web3_clientVersion` is valuable for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Avalanche client:', clientVersion);

// Using fetch
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

client_version = w3.client_version
print(f'Avalanche client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Avalanche client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/avalanche/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/avalanche/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/avalanche/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/avalanche/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Avalanche RPC Method

# web3_sha3 - Avalanche RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Avalanche.

> **Why Avalanche?** Build on the fastest smart contract platform with sub-second finality and customizable L1 subnets with sub-second finality, Evergreen subnets for institutions, and partnerships with Franklin Templeton, VanEck, and Bergen County.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for enterprise developers, RWA tokenizers, and teams building custom blockchain networks:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

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

const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/avalanche/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/avalanche/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/avalanche/web3_clientVersion) - Get node client version

---

## Base - Ethereum L2 Documentation

# Base - Ethereum L2 Documentation

## Base RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Base supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Base?

Base is Coinbase's Ethereum Layer 2 solution, designed to bring the next billion users onchain. Built on Optimism's OP Stack, Base offers:

### **Lightning Fast Performance**

- **200ms Flashblocks** - Sub-block preconfirmations every \~200ms via Flashblocks
- **10-100x lower costs** than Ethereum mainnet
- **EIP-4844 enabled** - Leveraging blob data for even lower fees

### **Enterprise Security**

- **Backed by Coinbase** - Institutional-grade infrastructure
- **Ethereum security** - Inherits L1 security guarantees
- **Battle-tested** - Built on proven Optimism technology

### **Massive Ecosystem**

- **1M+ weekly active users** - Rapidly growing user base
- **$2B+ TVL** - Strong DeFi ecosystem
- **Major integrations** - Circle USDC, Chainlink, The Graph

## Quick Start with Base

Connect to Base in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Base mainnet
const provider = new JsonRpcProvider(
  'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Base mainnet
const web3 = new Web3(
  'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Base:', chainId === 8453);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

// Create Base client
const client = createPublicClient({
  chain: base,
  transport: http('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value    | Details      |
| ------------ | -------- | ------------ |
| Chain ID     | 8453     | Mainnet      |
| Block Time   | \~200ms  | Flashblocks  |
| Gas Token    | ETH      | Native token |
| RPC Standard | Ethereum | JSON-RPC 2.0 |

## API Reference

Base supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) plus Base-specific Flashblocks methods and subscriptions.

## Flashblocks - 200ms Preconfirmations

Dwellir's Base endpoints support **Flashblocks**, delivering sub-block updates every \~200ms. Instead of waiting for a full 2-second block, your application can read preconfirmed state, stream pending transactions, and get receipts within milliseconds of submission.

### What You Get

| Capability                                                       | Description                                                                                                                                                   |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`"pending"` block tag**                                        | All state-reading methods (`eth_getBlockByNumber`, `eth_call`, `eth_getBalance`, `eth_getLogs`, etc.) accept `"pending"` to query the latest Flashblock state |
| **Preconfirmed receipts**                                        | `eth_getTransactionReceipt` returns receipts for transactions in the current Flashblock before the block is sealed                                            |
| **[`eth_sendRawTransactionSync`](https://www.dwellir.com/docs/eth_sendRawTransactionSync)** | Submit a transaction and get a full receipt synchronously in about 200ms                                                                                      |
| **[`eth_simulateV1`](https://www.dwellir.com/docs/eth_simulateV1)**                         | Simulate transaction bundles against the latest state with transfer tracing                                                                                   |
| **[`base_transactionStatus`](https://www.dwellir.com/docs/base_transactionStatus)**         | Check whether a transaction is still pending in the Base mempool                                                                                              |
| **WebSocket subscriptions**                                      | `newFlashblocks`, `newFlashblockTransactions`, and `pendingLogs` for real-time streaming                                                                      |

### Stream Flashblocks via WebSocket

newFlashblocks
newFlashblockTransactions
pendingLogs

```javascript
import WebSocket from 'ws';

const ws = new WebSocket('wss://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

ws.on('open', () => {
  // Stream full pending block state every ~200ms
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_subscribe',
    params: ['newFlashblocks'],
    id: 1,
  }));
});

ws.on('message', (data) => {
  const msg = JSON.parse(data);
  if (msg.params?.result) {
    const block = msg.params.result;
    console.log(`Flashblock #${parseInt(block.number, 16)} - ${block.transactions.length} txs`);
  }
});
```

```javascript
// Stream preconfirmed transaction hashes only
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  method: 'eth_subscribe',
  params: ['newFlashblockTransactions'],
  id: 1,
}));

// Or pass true to get full transaction objects with logs
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  method: 'eth_subscribe',
  params: ['newFlashblockTransactions', true],
  id: 2,
}));

ws.on('message', (data) => {
  const msg = JSON.parse(data);
  if (msg.params?.result) {
    const tx = msg.params.result;
    if (typeof tx === 'string') {
      console.log('Tx hash:', tx);
    } else {
      console.log('Full tx:', tx.hash, '- logs:', tx.logs.length);
    }
  }
});
```

```javascript
// Stream logs from preconfirmed transactions
// Optionally filter by address and topics
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  method: 'eth_subscribe',
  params: ['pendingLogs', {
    address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
    topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'],
  }],
  id: 1,
}));
```

### Query Preconfirmed State

Use the `"pending"` block tag to read state from the latest Flashblock:

```javascript
// Get balance reflecting the latest Flashblock
const balance = await provider.send('eth_getBalance', [address, 'pending']);

// Execute a call against Flashblock state
const result = await provider.send('eth_call', [{ to: contract, data: calldata }, 'pending']);

// Get logs from the current Flashblock
const logs = await provider.send('eth_getLogs', [{ fromBlock: 'pending', toBlock: 'pending' }]);
```

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // L2 specific: Check L1 data availability
  if (receipt.l1Fee) {
    console.log('L1 data cost:', receipt.l1Fee);
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Base L2:

```javascript
// Estimate L2 execution gas
const l2Gas = await provider.estimateGas(tx);

// Get current L1 data fee (Base specific)
const l1DataFee = await provider.send('eth_estimateL1Fee', [tx]);

// Total cost = L2 execution + L1 data posting
const totalCost = l2Gas + BigInt(l1DataFee);
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Base recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

---

## base_transactionStatus - Base RPC Method

# base_transactionStatus - Base RPC Method

Checks whether a transaction exists in the Base mempool. Returns `"Known"` if the transaction is pending in the mempool, or `"Unknown"` if it is not found (either already included in a block or never submitted).

This method is part of the `base_` namespace introduced with Flashblocks support.

Currently available on **Base Mainnet** only.

## Use Cases

- **Transaction tracking** — Check if a submitted transaction is still pending
- **Mempool monitoring** — Verify transaction propagation
- **Retry logic** — Determine whether to resubmit a transaction

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash to look up

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "base_transactionStatus",
  "params": ["0x..."],
  "id": 1
}
```

## Response Fields

- `status` (`String, required`): `"Known"` if the transaction is in the mempool, `"Unknown"` otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "Unknown"
  }
}
```

## Error Responses

### Invalid params

- Code: `-32602`
- Description: Invalid transaction hash format

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "base_transactionStatus",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
    "id": 1
  }'
```

```javascript
const response = await fetch(
  'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'base_transactionStatus',
      params: ['0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'],
      id: 1,
    }),
  }
);

const data = await response.json();
console.log('Transaction status:', data.result.status);
// "Known" = in mempool, "Unknown" = not in mempool
```

```python
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'base_transactionStatus',
        'params': ['0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'],
        'id': 1
    }
)

result = response.json()['result']
print(f"Status: {result['status']}")
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/base/eth_getTransactionByHash) — Get full transaction details
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/base/eth_getTransactionReceipt) — Get transaction receipt
- [`eth_sendRawTransactionSync`](https://www.dwellir.com/docs/base/eth_sendRawTransactionSync) — Send transaction with synchronous confirmation

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Base documentation](https://www.dwellir.com/docs/base).*

---

## debug_traceBlock - Base RPC Method

# debug_traceBlock - Base RPC Method

Traces all transactions in a block on Base by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Base - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Base
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Base:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Base blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/base/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/base/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/base/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/base/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Base RPC Method

# debug_traceBlockByHash - Base RPC Method

Traces all transactions in a block on Base identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Base - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Base
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Base:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Base:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/base/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/base/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/base/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/base/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/base/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Base RPC Method

# debug_traceBlockByNumber - Base RPC Method

Traces all transactions in a block on Base identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Base - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Base execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Base:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Base:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/base/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/base/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/base/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/base/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Base RPC Method

# debug_traceCall - Base RPC Method

Traces a call on Base without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Base - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Base
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Base to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Base:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Base:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/base/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/base/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/base/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/base/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Base RPC Method

# debug_traceTransaction - Base RPC Method

Traces a transaction execution on Base by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Base
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/base/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/base/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Base RPC Method

# eth_accounts - Base RPC Method

Returns a list of addresses owned by the client on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

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

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/base/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/base/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Base RPC Method

# eth_blockNumber - Base RPC Method

Returns the number of the most recent block on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_blockNumber` is fundamental for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Syncing Applications** - Keep your dApp in sync with the latest Base blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Base block:', blockNumber);

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Base block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Base block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Base block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Base block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Base:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Base:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Base node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/base/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/base/eth_syncing) - Check if node is still syncing

---

## eth_call - Base RPC Method

# eth_call - Base RPC Method

Executes a new message call immediately without creating a transaction on Base. Used for reading smart contract state.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

The `eth_call` method serves these key scenarios for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Base
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Base. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

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

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Base
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Base

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Base RPC Method

# eth_chainId - Base RPC Method

Returns the chain ID used for transaction signing on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_chainId` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/base/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/base/eth_syncing) - Check sync status

---

## eth_coinbase - Base RPC Method

# eth_coinbase - Base RPC Method

Checks the legacy `eth_coinbase` compatibility method on Base. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Base coinbase:', result);
}

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Base coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Base coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Base coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Base coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Base nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/base/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/base/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/base/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Base RPC Method

# eth_estimateGas - Base RPC Method

Estimates the gas necessary to execute a transaction on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Base
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Base.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

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

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Base may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

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

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

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

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

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

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/base/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 data posting fee

# eth_estimateL1Fee - Estimate L1 data posting fee

Estimate L1 data posting fee on the Base network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

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

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateL1Fee",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_estimateL1Fee',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_feeHistory - Base RPC Method

# eth_feeHistory - Base RPC Method

Returns historical gas fee data on Base, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Base without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Base.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Base) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

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

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

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

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/base/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/base/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Base RPC Method

# eth_gasPrice - Base RPC Method

Returns the current gas price on Base in wei.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Base
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Base. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Base, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Base: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Base supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

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

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

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

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

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

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/base/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/base/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Base RPC Method

# eth_getBalance - Base RPC Method

Returns the balance of a given address on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getBalance` is fundamental for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Base
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Base
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

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

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Base. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Base`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Base at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Base')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Base')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Base.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/base/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/base/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Base RPC Method

# eth_getBlockByHash - Base RPC Method

Returns information about a block by hash on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getBlockByHash` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Base
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Base.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Base.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const blockHash = '0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    blockHash := common.HexToHash("0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/base/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Base RPC Method

# eth_getBlockByNumber - Base RPC Method

Returns information about a block by block number on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getBlockByNumber` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Base
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Base with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Base. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

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

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

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

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/base/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/base/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/base/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Base RPC Method

# eth_getBlockReceipts - Base RPC Method

Returns all transaction receipts for a block on Base. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getBlockReceipts` is useful for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Base, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Base. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf47c4f664172629e9f74da58f558c6f553e2662adc7a3cf0af0292347bd2f358",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/base/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/base/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Base RPC Method

# eth_getCode - Base RPC Method

Returns the bytecode at a given address on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getCode` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Base
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Base:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Base:

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/base/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/base/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Base RPC Method

# eth_getFilterChanges - Base RPC Method

Polls a filter on Base for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getFilterChanges` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Base
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

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

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

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

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Base:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/base/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/base/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/base/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/base/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/base/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Base RPC Method

# eth_getFilterLogs - Base RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Base. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getFilterLogs` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Base
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/base/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/base/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/base/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/base/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Base RPC Method

# eth_getLogs - Base RPC Method

Returns an array of all logs matching a given filter object on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Base for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Base
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

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

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Base.

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

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Base enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Base, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

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

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

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

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

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

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/base/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/base/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Base RPC Method

# eth_getStorageAt - Base RPC Method

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

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getStorageAt` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **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 consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-base-mainnet-archive.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 = '0x4200000000000000000000000000000000000006'
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-base-mainnet-archive.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-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 Base:

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.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-base-mainnet-archive.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 = '0x4200000000000000000000000000000000000006';
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 Base:`);
  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/base/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/base/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/base/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Base RPC Method

# eth_getTransactionByHash - Base RPC Method

Returns the information about a transaction by transaction hash on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getTransactionByHash` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Base
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Base. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Base. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users.

```go
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client, _ := ethclient.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

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

const txHash = '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/base/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Base RPC Method

# eth_getTransactionCount - Base RPC Method

Returns the number of transactions sent from an address on Base, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getTransactionCount` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Base
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

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

## 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-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Base nonce:', nonce);

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

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

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'Base nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Base nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Base:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/base/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/base/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/base/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Base RPC Method

# eth_getTransactionReceipt - Base RPC Method

Returns the receipt of a transaction by transaction hash on Base. Receipt is only available for mined transactions.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_getTransactionReceipt` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Base and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Base. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

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

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Base, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

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

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

func main() {
    client, _ := ethclient.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const txHash = '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    txHash := common.HexToHash("0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/base/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/base/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Base RPC Method

# eth_hashrate - Base RPC Method

Returns the legacy `eth_hashrate` compatibility value on Base. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Base hashrate:', parseInt(payload.result, 16), 'H/s');
}

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Base hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Base hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Base hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Base hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/base/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/base/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/base/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Base RPC Method

# eth_maxPriorityFeePerGas - Base RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Base. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Base
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Base priority fee:', priorityFeeGwei, 'Gwei');

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Base priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

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

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

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

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Base priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Base:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

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

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Base:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/base/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/base/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/base/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Base RPC Method

# eth_mining - Base RPC Method

Checks the legacy `eth_mining` compatibility method on Base. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Base mining:', payload.result);
}

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Base mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Base mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Base mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Base mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/base/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/base/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/base/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Base RPC Method

# eth_newBlockFilter - Base RPC Method

Creates a filter on Base that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_newBlockFilter` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Block Monitoring** - Detect new blocks on Base as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

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

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

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Base:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/base/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/base/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/base/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/base/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Base RPC Method

# eth_newFilter - Base RPC Method

Creates a filter object on Base based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_newFilter` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Event Monitoring** - Subscribe to specific contract events on Base such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

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

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Base:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/base/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/base/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/base/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/base/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/base/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Base RPC Method

# eth_newPendingTransactionFilter - Base RPC Method

Creates a filter on Base that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Mempool Monitoring** - Observe unconfirmed transactions on Base to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Base...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Base:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/base/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/base/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/base/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Base RPC Method

# eth_protocolVersion - Base RPC Method

Returns the current Ethereum protocol version used by the Base node.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_protocolVersion` is useful for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Base protocol version:', version);

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

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Base protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Base protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Base protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Base protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Base nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/base/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/base/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/base/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Base RPC Method

# eth_sendRawTransaction - Base RPC Method

Submits a pre-signed transaction for broadcast to Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Base
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Base mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/base/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/base/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/base/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendRawTransactionSync - Base RPC Method

# eth_sendRawTransactionSync - Base RPC Method

Submits a signed transaction and **waits synchronously** for inclusion in a Flashblock before returning. Unlike [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) which returns immediately with just the transaction hash, this method blocks until the transaction is included in a Flashblock and returns a full transaction receipt.

This enables sub-200ms transaction confirmation flows — the response includes the receipt with `blockNumber`, `gasUsed`, `logs`, `status`, and L2-specific fields like `l1Fee`.

## Use Cases

- **Instant confirmation UX** — Display transaction results immediately without polling
- **Synchronous workflows** — Chain dependent operations without receipt polling
- **Payment processing** — Confirm payment transactions inline
- **Bot and MEV operations** — Confirm execution before proceeding

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransactionSync",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `transactionHash` (`DATA, required`): 32-byte transaction hash
- `blockHash` (`DATA, required`): 32-byte block hash (may be zero for preconfirmed blocks)
- `blockNumber` (`QUANTITY, required`): Block number the transaction was included in
- `gasUsed` (`QUANTITY, required`): Gas consumed by the transaction
- `status` (`QUANTITY, required`): `0x1` for success, `0x0` for revert
- `logs` (`Array, required`): Logs emitted by the transaction
- `l1Fee` (`QUANTITY, required`): L1 data posting fee charged
- `l1GasUsed` (`QUANTITY, required`): Gas used for L1 data posting

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "transactionHash": "0x...",
    "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "blockNumber": "0x29442e3",
    "gasUsed": "0x5208",
    "status": "0x1",
    "logs": [],
    "l1Fee": "0xa5fce0e0",
    "l1GasUsed": "0x34dc"
  }
}
```

## Error Responses

### Failed to decode signed transaction

- Code: `-32602`
- Description: Invalid RLP-encoded transaction data

### Nonce too low

- Code: `-32000`
- Description: Transaction nonce already used

### Insufficient funds

- Code: `-32000`
- Description: Account has insufficient balance

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransactionSync",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { Wallet, parseEther, JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Build and sign the transaction
const tx = await wallet.populateTransaction({
  to: '0x...',
  value: parseEther('0.01'),
});
const signedTx = await wallet.signTransaction(tx);

// Send synchronously — returns full receipt, not just hash
const receipt = await provider.send('eth_sendRawTransactionSync', [signedTx]);

console.log('Status:', receipt.status === '0x1' ? 'success' : 'reverted');
console.log('Block:', parseInt(receipt.blockNumber, 16));
console.log('Gas used:', parseInt(receipt.gasUsed, 16));
console.log('L1 fee:', parseInt(receipt.l1Fee, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')
tx = {
    'nonce': w3.eth.get_transaction_count(account.address),
    'to': '0x...',
    'value': w3.to_wei(0.01, 'ether'),
    'gas': 21000,
    'maxFeePerGas': w3.eth.gas_price,
    'maxPriorityFeePerGas': w3.eth.max_priority_fee,
    'chainId': 8453
}

signed_tx = account.sign_transaction(tx)

# Send synchronously — returns full receipt
receipt = w3.provider.make_request(
    'eth_sendRawTransactionSync',
    [signed_tx.raw_transaction.hex()]
)

print(f"Status: {receipt['result']['status']}")
print(f"Block: {int(receipt['result']['blockNumber'], 16)}")
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) — Async version (returns hash immediately)
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/base/eth_getTransactionReceipt) — Get receipt for a previously sent transaction
- [`eth_simulateV1`](https://www.dwellir.com/docs/base/eth_simulateV1) — Simulate transactions before sending

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Base documentation](https://www.dwellir.com/docs/base).*

---

## eth_sendTransaction - Base RPC Method

# eth_sendTransaction - Base RPC Method

Creates and sends a new transaction from an unlocked account on Base. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Base tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Base tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Base tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Base tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Base tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Base dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/base/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Base RPC Method

# eth_signTransaction - Base RPC Method

Signs a transaction with the private key of the specified account on Base without submitting it to the network.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Base tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Base tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

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

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Base tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Base:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/base/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/base/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/base/eth_accounts) - List accounts available for signing

---

## eth_simulateV1 - Base RPC Method

# eth_simulateV1 - Base RPC Method

Simulates one or more transaction bundles against Base state, including Flashblocks preconfirmed state. Returns simulated block results with call status, gas used, return data, logs, and errors — without broadcasting anything onchain.

## Use Cases

- **Transaction preview** — Verify a swap or transfer will succeed before sending
- **Multi-call simulation** — Simulate a sequence of dependent transactions atomically
- **State override testing** — Override account balances or contract storage for what-if analysis
- **Gas estimation** — Get precise gas usage for complex call sequences

## Request Parameters

- `simulatePayload` (`Object, required`): Object containing `blockStateCalls`, `traceTransfers`, and `validation`
- `blockTag` (`QUANTITY|TAG, required`): Block number in hex, or `"latest"`, `"pending"`

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_simulateV1",
  "params": [
    {
      "blockStateCalls": [
        {
          "calls": [
            {
              "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
              "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
              "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            }
          ]
        }
      ],
      "traceTransfers": true,
      "validation": false
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Simulated block number
- `hash` (`DATA, required`): Simulated block hash
- `gasUsed` (`QUANTITY, required`): Total gas used
- `calls` (`Array, required`): Array of call results

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "number": "0x29442bb",
      "hash": "0xcefc6e6e...",
      "gasUsed": "0x79ce",
      "calls": [
        {
          "returnData": "0x00000000000000000000000000000000000000000000000000000000011420f9",
          "logs": [],
          "gasUsed": "0x79ce",
          "status": "0x1"
        }
      ]
    }
  ]
}
```

## Error Responses

### Invalid params

- Code: `-32602`
- Description: Malformed simulation payload

### Execution reverted

- Code: `-32000`
- Description: One or more simulated calls reverted

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_simulateV1",
    "params": [
      {
        "blockStateCalls": [
          {
            "calls": [
              {
                "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
                "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
              }
            ]
          }
        ],
        "traceTransfers": true,
        "validation": false
      },
      "latest"
    ],
    "id": 1
  }'
```

```javascript
const response = await fetch(
  'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_simulateV1',
      params: [
        {
          blockStateCalls: [
            {
              calls: [
                {
                  from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
                  to: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
                  data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
                },
              ],
            },
          ],
          traceTransfers: true,
          validation: false,
        },
        'latest',
      ],
      id: 1,
    }),
  }
);

const data = await response.json();
for (const block of data.result) {
  for (const call of block.calls) {
    console.log('Status:', call.status === '0x1' ? 'success' : 'reverted');
    console.log('Gas used:', parseInt(call.gasUsed, 16));
    console.log('Return data:', call.returnData);
  }
}
```

```python
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_simulateV1',
        'params': [
            {
                'blockStateCalls': [
                    {
                        'calls': [
                            {
                                'from': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
                                'to': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
                                'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
                            }
                        ]
                    }
                ],
                'traceTransfers': True,
                'validation': False
            },
            'latest'
        ],
        'id': 1
    }
)

result = response.json()['result']
for block in result:
    for call in block['calls']:
        print(f"Status: {'success' if call['status'] == '0x1' else 'reverted'}")
        print(f"Gas used: {int(call['gasUsed'], 16)}")
        print(f"Return data: {call['returnData']}")
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/base/eth_call) — Execute a single read-only call
- [`eth_estimateGas`](https://www.dwellir.com/docs/base/eth_estimateGas) — Estimate gas for a transaction
- [`eth_sendRawTransactionSync`](https://www.dwellir.com/docs/base/eth_sendRawTransactionSync) — Send a transaction and wait for Flashblock inclusion

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Base documentation](https://www.dwellir.com/docs/base).*

---

## eth_syncing - Base RPC Method

# eth_syncing - Base RPC Method

Returns the sync status of your Base node - either `false` when fully synced, or an object describing the sync progress.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_syncing` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Base node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Base node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

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

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

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Base node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/base/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/base/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/base/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/base/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Base RPC Method

# eth_uninstallFilter - Base RPC Method

Removes a filter on Base that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`eth_uninstallFilter` is important for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/base/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/base/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/base/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/base/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/base/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Base RPC Method

# net_listening - Base RPC Method

Checks whether the connected Base client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`net_listening` is useful for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

try {
  const listening = await provider.send('net_listening', []);
  console.log('Base node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Base node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Base node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/base/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/base/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/base/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/base/web3_clientVersion) - Get node client info

---

## net_peerCount - Base RPC Method

# net_peerCount - Base RPC Method

Returns the number of peers currently connected to your Base node.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`net_peerCount` is important for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Base deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Base peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Base peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

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

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Base peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Base nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/base/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/base/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/base/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/base/web3_clientVersion) - Get node client info

---

## net_version - Base RPC Method

# net_version - Base RPC Method

Returns the current network ID on Base as a decimal string. The network ID identifies which network the node is connected to.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`net_version` is essential for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Endpoint Identification** - Confirm your application is connected to the expected Base network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

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

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const networkId = await provider.send('net_version', []);
console.log('Base network ID:', networkId);

// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Base network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

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

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Base network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/base/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/base/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/base/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/base/eth_syncing) - Check node sync progress

---

## rollup_gasPrices - Get L2 gas price oracle data

# rollup_gasPrices - Get L2 gas price oracle data

Get L2 gas price oracle data on the Base network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

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

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_gasPrices",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_gasPrices',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## rollup_getInfo - Get rollup configuration

# rollup_getInfo - Get rollup configuration

Get rollup configuration on the Base network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_getInfo",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

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

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_getInfo",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_getInfo',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## trace_block - Base RPC Method

# trace_block - Base RPC Method

Returns traces for all transactions in a block on Base.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Base
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Base chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/base/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/base/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/base/trace_get) - Get a specific trace by index

---

## trace_call - Base RPC Method

# trace_call - Base RPC Method

Traces a call without creating a transaction on Base, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Base
- **Pre-execution analysis** - Test contract interactions without spending gas for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x4200000000000000000000000000000000000006", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const result = await provider.send('trace_call', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x4200000000000000000000000000000000000006',
        'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/base/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/base/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/base/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Base RPC Method

# trace_callMany - Base RPC Method

Traces multiple calls in sequence on Base, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Base
- **Historical state comparison** - Compare how the same call would execute at different points in Base chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x4200000000000000000000000000000000000006", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"}, ["trace"]],
      [{"to": "0x4200000000000000000000000000000000000006", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x4200000000000000000000000000000000000006", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"}, ["trace"]],
        [{"to": "0x4200000000000000000000000000000000000006", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x4200000000000000000000000000000000000006', data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006' }, ['trace']],
    [{ to: '0x4200000000000000000000000000000000000006', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x4200000000000000000000000000000000000006', 'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'}, ['trace']],
        [{'to': '0x4200000000000000000000000000000000000006', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/base/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/base/eth_call) - Execute call without trace

---

## trace_filter - Base RPC Method

# trace_filter - Base RPC Method

Returns traces matching a filter on Base.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Base
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x4200000000000000000000000000000000000006"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x4200000000000000000000000000000000000006"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x4200000000000000000000000000000000000006'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x4200000000000000000000000000000000000006'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/base/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/base/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/base/eth_getLogs) - Filter event logs

---

## trace_get - Base RPC Method

# trace_get - Base RPC Method

Returns a trace at a specific position within a transaction on Base.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Base
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const trace = await provider.send('trace_get', [
  '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/base/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/base/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Base RPC Method

# trace_replayBlockTransactions - Base RPC Method

Replays all transactions in a block on Base and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Base
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Base chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/base/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/base/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/base/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Base RPC Method

# trace_replayTransaction - Base RPC Method

Replays a transaction on Base and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Base
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const result = await provider.send('trace_replayTransaction', [
  '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/base/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/base/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/base/trace_block) - Get all traces in a block

---

## trace_transaction - Base RPC Method

# trace_transaction - Base RPC Method

Returns all traces for a specific transaction on Base.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for consumer dApps, SocialFi, NFT marketplaces, and merchant payment integrations
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Base
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

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

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const traces = await provider.send('trace_transaction', [
  '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/base/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/base/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/base/trace_filter) - Filter traces by criteria

---

## web3_clientVersion - Base RPC Method

# web3_clientVersion - Base RPC Method

Returns the current client software version string for your Base node, including the client name, version number, OS, and runtime.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

## When to Use This Method

`web3_clientVersion` is valuable for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

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

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Base client:', clientVersion);

// Using fetch
const response = await fetch('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Base client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Base client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/base/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/base/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/base/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/base/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Base RPC Method

# web3_sha3 - Base RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Base.

> **Why Base?** Build on Coinbase's L2 with 54% of L2 market revenue and direct access to 110M+ Coinbase users with $8B+ TVL, $0.08 gas fees, built-in Coinbase distribution, and seamless fiat rails.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for consumer app developers, SocialFi builders, and teams seeking easy fiat onramps:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-base-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/base/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/base/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/base/web3_clientVersion) - Get node client version

---

## Berachain RPC with Dwellir

# Berachain RPC with Dwellir

## Berachain RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Berachain supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Berachain?

### High‑Performance EVM

- Built on a modular EVM (Polaris) for efficient execution and developer‑friendly precompiles
- Fast finality via CometBFT (BFT consensus), ideal for low‑latency reads and responsive UX
- EVM compatibility out of the box. Keep using Solidity, Hardhat, Foundry, viem, and ethers.js

### Proof‑of‑Liquidity Alignment

- Separation of gas and governance unlocks healthier incentive design
- Liquidity provision powers governance emissions (BGT) to align validators, protocols, and users
- Ecosystem‑driven rewards encourage deep liquidity for DeFi building blocks

### Interoperability & Modularity

- Cosmos SDK foundation with IBC‑friendly architecture for cross‑chain connectivity
- Polaris EVM’s modular design enables stateful precompiles and chain‑specific extensions without breaking EVM apps
- Drop‑in migration: reuse your contracts, tooling, and workflows

## Quick Start with Berachain

Connect to Berachain in seconds with Dwellir's optimized endpoints:

### Installation & Setup

cURL
Ethers.js v6
Viem
Python (web3.py)

```bash
# Check latest block
curl -s -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Verify chain id
curl -s -X POST https://api-berachain-bepolia.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
```

```ts
import { JsonRpcProvider } from 'ethers';

// Mainnet
const mainnet = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
console.log(await mainnet.getBlockNumber());
console.log((await mainnet.getNetwork()).chainId); // 80094

// Bepolia testnet
const bepolia = new JsonRpcProvider('https://api-berachain-bepolia.n.dwellir.com/YOUR_API_KEY');
console.log(await bepolia.getBlockNumber());
console.log((await bepolia.getNetwork()).chainId); // 80069
```

```ts
import { createPublicClient, http, parseEther } from 'viem';

const mainnet = createPublicClient({
  transport: http('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

const blockNumber = await mainnet.getBlockNumber();
const balance = await mainnet.getBalance({ address: '0x0000000000000000000000000000000000000000' });
```

```py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
assert w3.is_connected()
print(w3.eth.chain_id)      # 80094
print(w3.eth.block_number)
```

## Network Information

| Parameter        | Value                 | Details           |
| ---------------- | --------------------- | ----------------- |
| Mainnet Chain ID | 80094 (0x138de)       | Berachain Mainnet |
| Testnet Chain ID | 80069 (0x138c5)       | Bepolia Testnet   |
| RPC Standard     | Ethereum JSON-RPC 2.0 | EVM-compatible    |

## API Reference

Berachain supports the full [Ethereum JSON-RPC API](https://ethereum.org/developers/docs/apis/json-rpc/).

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
async function waitForConfirmations(provider, txHash, confirmations = 1) {
  const receipt = await provider.waitForTransaction(txHash, confirmations);
  return receipt;
}
```

### Gas Optimization

Use EIP‑1559 dynamic fees and estimate execution gas:

```javascript
const feeData = await provider.getFeeData();
const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: await provider.estimateGas({ to: recipient, value: amount }),
};
```

### Event Filtering

Query events in bounded ranges to avoid overfetching:

```javascript
async function getEvents(contract, filter, fromBlock, toBlock, batchSize = 2000) {
  const events = [];
  for (let i = fromBlock; i <= toBlock; i += batchSize) {
    const batch = await contract.queryFilter(filter, i, Math.min(i + batchSize - 1, toBlock));
    events.push(...batch);
  }
  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine independent calls in a single POST to reduce round‑trips:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const res = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});
const results = await res.json();
```

### 2. **Connection Pooling**

Reuse provider/clients instead of recreating per call:

```ts
import { JsonRpcProvider } from 'ethers';

class BeraProvider {
  static instance: JsonRpcProvider | null = null;
  static get() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data (e.g., past blocks, ABIs) and debounce hot paths:

```ts
const cache = new Map<string, unknown>();
async function getBlockCached(n: number) {
  const k = `block_${n}`;
  if (!cache.has(k)) {
    cache.set(k, await BeraProvider.get().getBlock(n));
  }
  return cache.get(k);
}
```

## Migration Guide

Moving from Ethereum or another EVM chain typically requires:

- Update RPC URL to the Berachain mainnet endpoint: `https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY`
- Verify chain ID via `eth_chainId` (0x138de mainnet) before sending transactions
- Re-check gas settings (EIP‑1559) and any hard‑coded addresses

```ts
// Before
const provider = new JsonRpcProvider('https://eth.example');

// After (Berachain mainnet)
const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
```

## Resources & Tools

- [Berachain Docs](https://docs.berachain.com/)
- [Dwellir Dashboard](https://dashboard.dwellir.com)
- [Dwellir Support](mailto:support@dwellir.com)

### Related Reading

- [Top 7 Berachain RPC Providers 2026](https://www.dwellir.com/blog/top-berachain-rpc-providers)

## Troubleshooting Common Issues

- Wrong chain: ensure `eth_chainId` returns `0x138de` (mainnet) or `0x138c5` (Bepolia).
- Hex quantities: send and parse `0x`-prefixed hex strings (no leading zeros).
- Timeouts/rate limits: implement retries with exponential backoff on HTTP 429 or -32005.

## FAQs

- Do I need an API key? Yes, append `/YOUR_API_KEY` to all endpoints.
- WebSockets? Use HTTP endpoints above; WebSocket availability may vary.
- Explorers/faucets? N/A.

## Smoke Tests

- curl: `eth_blockNumber` to both endpoints returns `result: "0x..."`.
- ethers v6: `getBlockNumber()` resolves; `getNetwork().chainId` equals 80094 or 80069.
- web3.py: `is_connected()` is True; `chain_id` and `block_number` query succeed.

***

Start building on Berachain with Dwellir’s reliable RPC.

---

## debug_traceBlock - Berachain RPC Method

# debug_traceBlock - Berachain RPC Method

Traces all transactions in a block on Berachain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Berachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Berachain
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Berachain:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Berachain blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/berachain/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/berachain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/berachain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/berachain/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Berachain RPC Method

# debug_traceBlockByHash - Berachain RPC Method

Traces all transactions in a block on Berachain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Berachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Berachain
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Berachain:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Berachain:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/berachain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/berachain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/berachain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/berachain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/berachain/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Berachain RPC Method

# debug_traceBlockByNumber - Berachain RPC Method

Traces all transactions in a block on Berachain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Berachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Berachain execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Berachain:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Berachain:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/berachain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/berachain/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/berachain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/berachain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Berachain RPC Method

# debug_traceCall - Berachain RPC Method

Traces a call on Berachain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Berachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Berachain
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
        "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
        "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    data: '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    data: '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    'data': '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
        "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Berachain to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Berachain:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Berachain:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/berachain/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/berachain/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/berachain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/berachain/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Berachain RPC Method

# debug_traceTransaction - Berachain RPC Method

Traces a transaction execution on Berachain by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Berachain
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/berachain/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/berachain/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Berachain RPC Method

# eth_accounts - Berachain RPC Method

Returns a list of addresses owned by the client on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/berachain/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/berachain/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Berachain RPC Method

# eth_blockNumber - Berachain RPC Method

Returns the number of the most recent block on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Syncing Applications** - Keep your dApp in sync with the latest Berachain blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Berachain block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Berachain block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Berachain block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Berachain block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Berachain block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Berachain:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Berachain:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Berachain node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/berachain/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/berachain/eth_syncing) - Check if node is still syncing

---

## eth_call - Berachain RPC Method

# eth_call - Berachain RPC Method

Executes a new message call immediately without creating a transaction on Berachain. Used for reading smart contract state.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Berachain
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';
const walletAddress = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Berachain. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Berachain
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Berachain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    data := common.FromHex("0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Berachain RPC Method

# eth_chainId - Berachain RPC Method

Returns the chain ID used for transaction signing on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_chainId` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/berachain/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/berachain/eth_syncing) - Check sync status

---

## eth_coinbase - Berachain RPC Method

# eth_coinbase - Berachain RPC Method

Checks the legacy `eth_coinbase` compatibility method on Berachain. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Berachain coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Berachain coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Berachain coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Berachain coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Berachain coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Berachain nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/berachain/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/berachain/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/berachain/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Berachain RPC Method

# eth_estimateGas - Berachain RPC Method

Estimates the gas necessary to execute a transaction on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Berachain
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Berachain.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Berachain may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/berachain/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Berachain RPC Method

# eth_feeHistory - Berachain RPC Method

Returns historical gas fee data on Berachain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Berachain without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Berachain.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Berachain) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/berachain/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/berachain/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Berachain RPC Method

# eth_gasPrice - Berachain RPC Method

Returns the current gas price on Berachain in wei.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Berachain
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Berachain. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Berachain, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Berachain: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Berachain supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/berachain/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/berachain/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Berachain RPC Method

# eth_getBalance - Berachain RPC Method

Returns the balance of a given address on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Berachain
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Berachain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Berachain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Berachain`);
  return balance;
}

displayBalance('0x7507c1dc16935B82698e4C63f2746A2fCf994dF8');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Berachain at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Berachain')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Berachain')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Berachain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/berachain/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/berachain/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Berachain RPC Method

# eth_getBlockByHash - Berachain RPC Method

Returns information about a block by hash on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Berachain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Berachain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Berachain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Berachain RPC Method

# eth_getBlockByNumber - Berachain RPC Method

Returns information about a block by block number on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Berachain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Berachain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Berachain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/berachain/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/berachain/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Berachain RPC Method

# eth_getBlockReceipts - Berachain RPC Method

Returns all transaction receipts for a block on Berachain. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Berachain, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Berachain. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x969b796c2c98668e687636319dba231c7f3f77e1c89dab82fba3d17f8f0f9e55",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/berachain/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/berachain/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Berachain RPC Method

# eth_getCode - Berachain RPC Method

Returns the bytecode at a given address on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getCode` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Berachain
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Berachain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Berachain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/berachain/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/berachain/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Berachain RPC Method

# eth_getFilterChanges - Berachain RPC Method

Polls a filter on Berachain for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Berachain
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Berachain:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/berachain/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/berachain/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/berachain/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/berachain/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/berachain/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Berachain RPC Method

# eth_getFilterLogs - Berachain RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Berachain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Berachain
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/berachain/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/berachain/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/berachain/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/berachain/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Berachain RPC Method

# eth_getLogs - Berachain RPC Method

Returns an array of all logs matching a given filter object on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Berachain for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Berachain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Berachain.

```javascript
const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Berachain enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Berachain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/berachain/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/berachain/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Berachain RPC Method

# eth_getStorageAt - Berachain RPC Method

Returns the value from a storage position at a given address on Berachain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **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 liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **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": [
    "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "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-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', '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-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';

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-berachain-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 = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
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-berachain-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-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    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 Berachain:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-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-berachain-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 = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';
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 Berachain:`);
  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/berachain/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/berachain/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/berachain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Berachain RPC Method

# eth_getTransactionByHash - Berachain RPC Method

Returns the information about a transaction by transaction hash on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Berachain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Berachain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Berachain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/berachain/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Berachain RPC Method

# eth_getTransactionCount - Berachain RPC Method

Returns the number of transactions sent from an address on Berachain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Berachain
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Berachain nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
nonce = get_transaction_count(address)
print(f'Berachain nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Berachain nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Berachain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/berachain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/berachain/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/berachain/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Berachain RPC Method

# eth_getTransactionReceipt - Berachain RPC Method

Returns the receipt of a transaction by transaction hash on Berachain. Receipt is only available for mined transactions.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Berachain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Berachain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Berachain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/berachain/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/berachain/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Berachain RPC Method

# eth_hashrate - Berachain RPC Method

Returns the legacy `eth_hashrate` compatibility value on Berachain. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Berachain hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Berachain hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Berachain hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Berachain hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Berachain hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/berachain/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/berachain/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Berachain RPC Method

# eth_maxPriorityFeePerGas - Berachain RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Berachain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Berachain
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Berachain priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Berachain priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Berachain priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Berachain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Berachain:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/berachain/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/berachain/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/berachain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Berachain RPC Method

# eth_mining - Berachain RPC Method

Checks the legacy `eth_mining` compatibility method on Berachain. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Berachain mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Berachain mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Berachain mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Berachain mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Berachain mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/berachain/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/berachain/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Berachain RPC Method

# eth_newBlockFilter - Berachain RPC Method

Creates a filter on Berachain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Block Monitoring** - Detect new blocks on Berachain as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Berachain:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/berachain/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/berachain/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/berachain/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Berachain RPC Method

# eth_newFilter - Berachain RPC Method

Creates a filter object on Berachain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_newFilter` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Event Monitoring** - Subscribe to specific contract events on Berachain such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Berachain:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/berachain/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/berachain/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/berachain/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/berachain/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/berachain/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Berachain RPC Method

# eth_newPendingTransactionFilter - Berachain RPC Method

Creates a filter on Berachain that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on Berachain to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Berachain...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Berachain:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/berachain/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/berachain/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/berachain/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Berachain RPC Method

# eth_protocolVersion - Berachain RPC Method

Returns the current Ethereum protocol version used by the Berachain node.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Berachain protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Berachain protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Berachain protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Berachain protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Berachain protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Berachain nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/berachain/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/berachain/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/berachain/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Berachain RPC Method

# eth_sendRawTransaction - Berachain RPC Method

Submits a pre-signed transaction for broadcast to Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Berachain
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Berachain mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/berachain/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x7507c1dc16935B82698e4C63f2746A2fCf994dF8")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/berachain/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/berachain/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Berachain RPC Method

# eth_sendTransaction - Berachain RPC Method

Creates and sends a new transaction from an unlocked account on Berachain. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Berachain tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Berachain tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Berachain tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Berachain tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Berachain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Berachain dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/berachain/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/berachain/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Berachain RPC Method

# eth_signTransaction - Berachain RPC Method

Signs a transaction with the private key of the specified account on Berachain without submitting it to the network.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Berachain tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Berachain tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Berachain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Berachain:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/berachain/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/berachain/eth_accounts) - List accounts available for signing

---

## eth_syncing - Berachain RPC Method

# eth_syncing - Berachain RPC Method

Returns the sync status of your Berachain node - either `false` when fully synced, or an object describing the sync progress.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_syncing` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Berachain node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Berachain node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Berachain node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/berachain/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/berachain/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/berachain/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Berachain RPC Method

# eth_uninstallFilter - Berachain RPC Method

Removes a filter on Berachain that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/berachain/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/berachain/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/berachain/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/berachain/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/berachain/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Berachain RPC Method

# net_listening - Berachain RPC Method

Checks whether the connected Berachain client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`net_listening` is useful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Berachain node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Berachain node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Berachain node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/berachain/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/berachain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/berachain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/berachain/web3_clientVersion) - Get node client info

---

## net_peerCount - Berachain RPC Method

# net_peerCount - Berachain RPC Method

Returns the number of peers currently connected to your Berachain node.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`net_peerCount` is important for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Berachain deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Berachain peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Berachain peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Berachain peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Berachain nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/berachain/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/berachain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/berachain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/berachain/web3_clientVersion) - Get node client info

---

## net_version - Berachain RPC Method

# net_version - Berachain RPC Method

Returns the current network ID on Berachain as a decimal string. The network ID identifies which network the node is connected to.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`net_version` is essential for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Endpoint Identification** - Confirm your application is connected to the expected Berachain network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Berachain network ID:', networkId);

// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Berachain network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Berachain network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/berachain/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/berachain/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/berachain/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/berachain/eth_syncing) - Check node sync progress

---

## rpc_modules - Berachain RPC Method

# rpc_modules - Berachain RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Berachain endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`rpc_modules` is useful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/berachain/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/berachain/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/berachain/trace_transaction) - Trace namespace example

---

## trace_block - Berachain RPC Method

# trace_block - Berachain RPC Method

Returns traces for all transactions in a block on Berachain.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Berachain
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Berachain chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/berachain/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/berachain/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/berachain/trace_get) - Get a specific trace by index

---

## trace_call - Berachain RPC Method

# trace_call - Berachain RPC Method

Traces a call without creating a transaction on Berachain, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Berachain
- **Pre-execution analysis** - Test contract interactions without spending gas for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8",
      "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8", "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
    data: '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8',
        'data': '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/berachain/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/berachain/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/berachain/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Berachain RPC Method

# trace_callMany - Berachain RPC Method

Traces multiple calls in sequence on Berachain, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Berachain
- **Historical state comparison** - Compare how the same call would execute at different points in Berachain chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8", "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"}, ["trace"]],
      [{"to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8", "data": "0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8"}, ["trace"]],
        [{"to": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', data: '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8' }, ['trace']],
    [{ to: '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', 'data': '0x70a082310000000000000000000000007507c1dc16935B82698e4C63f2746A2fCf994dF8'}, ['trace']],
        [{'to': '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/berachain/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/berachain/eth_call) - Execute call without trace

---

## trace_filter - Berachain RPC Method

# trace_filter - Berachain RPC Method

Returns traces matching a filter on Berachain.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Berachain
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x7507c1dc16935B82698e4C63f2746A2fCf994dF8"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x7507c1dc16935B82698e4C63f2746A2fCf994dF8"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/berachain/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/berachain/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/berachain/eth_getLogs) - Filter event logs

---

## trace_get - Berachain RPC Method

# trace_get - Berachain RPC Method

Returns a trace at a specific position within a transaction on Berachain.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Berachain
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/berachain/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/berachain/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Berachain RPC Method

# trace_replayBlockTransactions - Berachain RPC Method

Replays all transactions in a block on Berachain and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Berachain
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Berachain chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/berachain/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/berachain/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/berachain/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Berachain RPC Method

# trace_replayTransaction - Berachain RPC Method

Replays a transaction on Berachain and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Berachain
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/berachain/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/berachain/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/berachain/trace_block) - Get all traces in a block

---

## trace_transaction - Berachain RPC Method

# trace_transaction - Berachain RPC Method

Returns all traces for a specific transaction on Berachain.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for liquidity-aligned DeFi (Infrared, Kodiak), yield farming, and validator-integrated liquidity incentives
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Berachain
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0xc5c421e9e1f89c46d6f23e4057f24ed39fe8c8d75f0dc27159b46f8b6ece3671'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/berachain/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/berachain/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/berachain/trace_filter) - Filter traces by criteria

---

## txpool_content - Berachain RPC Method

# txpool_content - Berachain RPC Method

Returns the full pending and queued transaction pool for the connected Berachain endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`txpool_content` is useful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/berachain/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/berachain/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/berachain/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Berachain RPC Method

# txpool_status - Berachain RPC Method

Returns transaction pool counters for the connected Berachain endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`txpool_status` is valuable for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/berachain/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/berachain/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/berachain/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Berachain RPC Method

# web3_clientVersion - Berachain RPC Method

Returns the current client software version string for your Berachain node, including the client name, version number, OS, and runtime.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Berachain client:', clientVersion);

// Using fetch
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Berachain client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Berachain client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/berachain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/berachain/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/berachain/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/berachain/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Berachain RPC Method

# web3_sha3 - Berachain RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Berachain.

> **Why Berachain?** Build on the Proof-of-Liquidity L1 with $3.2B+ TVL and innovative three-token economics with Proof-of-Liquidity consensus, three-token model (BERA/BGT/HONEY), $142M funding, and unified validator-DeFi incentive alignment.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi protocol developers, liquidity providers, and teams building yield-optimized applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/berachain/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/berachain/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/berachain/web3_clientVersion) - Get node client version

---

## Bifrost Liquid Staking Parachain RPC Guide

# Bifrost Liquid Staking Parachain RPC Guide

## Bifrost RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Bifrost supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Bifrost?

Bifrost is Polkadot's liquid staking hub, issuing omni-chain vTokens that unlock staking liquidity while keeping rewards flowing. Builders target Bifrost because it delivers:

### **Omni-Chain Liquidity Routing**

- Staking Liquidity Protocol (SLP) mints yield-bearing vTokens (vDOT, vKSM, vETH, vFIL) that stay composable across parachains and EVM networks.
- Slot Auction Liquidity Protocol (SALP) releases DOT/KSM crowdloan positions into tradable derivatives, letting users support auctions without sacrificing liquidity.
- Liquid staking primitives integrate with major DeFi venues (Pendle, Loop Stake, Talisman, etc.) to optimize leverage and hedging strategies.

### **Protocol-Neutral Architecture**

- Dedicated pallets for cross-chain execution (ISMP, CrossInOut, Hyperbridge) make it easy to bridge liquidity between Polkadot, Kusama, and external EVMs.
- Governance and fee-share pallets align collators, liquidity providers, and derivative users through on-chain revenue distribution.
- Runtime upgrades (v0.21.1 / specVersion 21001) focus on async backing, Hyperbridge routes, and tokenomics 2.0 for sustained reward flows.

### **Battle-Tested Operations**

- Active collator set with \~6 s block time keeps derivatives in sync with relay-chain finality.
- Proven SALP campaigns unlock DOT crowdloans while maintaining reward accrual.
- Continuous grant support and ecosystem partnerships accelerate tooling and collateral adoption.

## Quick Start with Bifrost

Connect to mainnet or the Kusama canary network in seconds using Dwellir-managed infrastructure.

The Kusama deployment (Para ID 2001) runs identical pallets ahead of Polkadot releases. Use it for SALP dry-runs, Hyperbridge testing, and upgrade rehearsals before promoting to mainnet Para ID 2030.

### Installation & Setup

cURL
JavaScript (polkadot.js)
Rust (subxt)
Python (py-substrate-interface)

```bash
curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "chain_getHeader",
    "params": []
  }'
```

**Expected output (captured 2025-10-03):**

```json
{
  "jsonrpc": "2.0",
  "result": {
    "number": "0x9055f2",
    "hash": "0xd4b3a0e3b88b7c25215926bbf7c733f5c31e69c0c8c4b4a86d6ec3f3f086e95d",
    "parentHash": "0x65b246e9b69a61f842104a15307ae906013c56a8bb6c942555b1a71424b4bab3",
    "stateRoot": "0x220ea5bd35df99176268d8cbcee287a8a81a2e8addfa764661f71af591db0329",
    "extrinsicsRoot": "0x388e5e2bb951b1dfac3f6a3f0c1d5de1ace6e413008efe48f1a54228dcd049db"
  },
  "id": 1
}
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function main() {
  const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });

  const [chain, nodeName, nodeVersion, runtime] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.state.getRuntimeVersion()
  ]);

  console.log(`Connected to ${chain.toString()} via ${nodeName.toString()} ${nodeVersion.toString()}`);
  console.log(`Runtime specVersion=${runtime.specVersion.toNumber()} transactionVersion=${runtime.transactionVersion.toNumber()}`);

  const header = await api.rpc.chain.getHeader();
  console.log(`Latest head #${header.number.toString()} (${header.hash.toHex()})`);

  await api.disconnect();
}

main().catch(console.error);
```

```rust
use subxt::{config::substrate::SubstrateConfig, OnlineClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<SubstrateConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let latest = api.rpc().header(None).await?.expect("header");
    println!("Finalized block #{}", latest.number);
    println!("State root {}", latest.state_root);

    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(
    url="wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY",
    type_registry_preset="substrate-node-template"
)

latest_hash = substrate.get_chain_head()
print("Latest head:", latest_hash)

runtime = substrate.get_runtime_version()
print("specVersion:", runtime['specVersion'], "transactionVersion:", runtime['transactionVersion'])

account_info = substrate.query(
    module='System',
    storage_function='Account',
    params=['15mYsj6DpBno58jRoV5HCTiVPFBuWhDLdsWtq3LxwZrfaTEZ']
)
print("Collator free balance:", account_info.value['data']['free'])
```

## API Reference

Bifrost exposes the standard Substrate namespaces for node telemetry, finality, storage, extrinsic submission, and runtime metadata, alongside specialized pallets such as `Hyperbridge`, `FlexibleFee`, `Farming`, and `Ismp`.

## Network Information

| Parameter                | Bifrost (Polkadot Mainnet)                                           | Bifrost (Kusama Canary)                                              |
| ------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **Relay Chain**          | Polkadot                                                             | Kusama                                                               |
| **Parachain ID**         | 2030                                                                 | 2001                                                                 |
| **Genesis Hash**         | `0x262e1b2ad728475fd6fe88e62d34c200abe6fd693931ddad144059b1eb884e5b` | `0x9f28c6a68e0fc9646eff64935684f6eeeece527e37bbe1f213d22caa1d9d6bed` |
| **Runtime (2025-10-03)** | specVersion `21001`, transactionVersion `1`                          | specVersion `19000`, transactionVersion `1`                          |
| **Unit Symbol**          | BNC                                                                  | BNC                                                                  |
| **Decimals**             | 12                                                                   | 12                                                                   |
| **SS58 Prefix**          | 6                                                                    | 6                                                                    |
| **Explorer**             | bifrost.subscan.io                                                   | bifrost-kusama.subscan.io                                            |
| **Average Block Time**   | \~6 seconds                                                          | \~6 seconds                                                          |

### Additional Details

| Parameter         | Value                                               | Details                                        |
| ----------------- | --------------------------------------------------- | ---------------------------------------------- |
| Collator Rotation | >16 active authors                                  | RefTime utilization stays under 0.5% per block |
| Runtime Pallets   | `Hyperbridge`, `FlexibleFee`, `Farming`, and `Ismp` | Cross-ecosystem liquidity orchestration        |

## Common Integration Patterns

### Real-Time Block Streaming

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New Bifrost block #${header.number.toString()} (${header.hash.toHex()})`);
});
```

### Query Staking Liquidity Positions

```bash
# Read total issuance for vDOT (AssetRegistry + Tokens pallet)
curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":42,
    "method":"state_getStorage",
    "params":[
      "0x1bd4a27d04bdb9c3f135c3b09677626d26c37dd72647d0f2788a3341e9ac1371"
    ]
  }'
```

### Estimate Fees for SALP Transfers

```typescript
const api = await ApiPromise.create({ provider: new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY') });

const tx = api.tx.crossInOut.swapExactAssetsForAssets(
  /* asset_in */ { Xcm: { V3: { parents: 1, interior: 'Here' } } },
  /* asset_out */ { Token: 'BNC' },
  /* amount */ 1_000_000_000_000n,
  /* min_receive */ 990_000_000_000n
);

const info = await api.rpc.payment.queryInfo(tx.toHex());
console.log(`Partial fee: ${info.partialFee.toHuman()}`);
console.log(`Weight: ${info.weight.refTime.toString()} refTime`);
```

## Performance Best Practices

- Prefer WebSocket endpoints for subscriptions and long-lived queries; use HTTPS for bursty read-only workloads.
- Cache runtime metadata and type registries keyed by `specVersion` (Polkadot `21001`, Kusama `19000` as of 2025-10-03) to avoid repeated handshakes.
- Use `state_getKeysPaged` with sized pages (<1024 keys) when scanning liquidity pools or reward ledgers.
- Pin to finalized heads for settlement-critical reads; leverage `chain_getFinalizedHead` before fetching block data.
- Implement jittered reconnect backoff (250 ms → 8 s) to respect Dwellir rate limiting during failover events.

## Troubleshooting

| Symptom                                                       | Likely Cause                                                       | Resolution                                                                                     |
| ------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `1010: Invalid Transaction` when submitting vToken extrinsics | Runtime upgrade bumped `specVersion`/`transactionVersion`          | Refresh metadata, rebuild the payload, and resubmit with the updated version info              |
| `Invalid SS58 address` errors                                 | Using Polkadot prefix (`0`) for Bifrost accounts                   | Re-derive addresses with SS58 prefix `6` before signing or decoding                            |
| `TypeError: Cannot decode storage`                            | Missing custom pallets (Hyperbridge, FlexibleFee) in type registry | Extend your type bundle with the latest Bifrost runtime metadata                               |
| Persistent WebSocket disconnects                              | Idle connection without keep-alives                                | Send periodic heartbeats (e.g., `rpc_methods`) or enable `WsProvider` autoConnect              |
| `Authoring not allowed for account` on collator nodes         | Rotate keys not submitted after upgrade                            | Call `author_rotateKeys` and `parachainStaking.setKeys` on the canary network, then on mainnet |

## Smoke Tests

Run these checks before pushing to production:

1. **Node health**
   ```bash
   curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}'
   ```
   Verify `isSyncing` is `false` and peer count stays above 8.

2. **Latest header increments**
   ```bash
   curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":2,"method":"chain_getHeader","params":[]}'
   ```
   Confirm block numbers advance \~every 6 seconds (e.g., #9,053,714 at 2025-10-03 07:42:18 UTC).

3. **Account snapshot**
   ```bash
   curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":3,"method":"state_getStorage","params":["0x26aa394eea5630e07c48ae0c9558cef7f0d3720dbb6f7b3bb82b41c16dbf8d0887f21b38c918a1962fa4273d0f3c2c23244cc25f029aba80a72f1ac277957bc4"]}'
   ```
   Decode the SCALE payload to check BNC balances (collator `15mYsj6…TEZ` shows active staking reserves).

## Migration Guide (Polkadot/Westend → Bifrost)

- **Endpoints:** Swap legacy Polkadot URLs for `https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY`. Use the Kusama canary endpoint for staging.
- **Address encoding:** Update wallets and services to SS58 prefix `6` for Bifrost accounts.
- **Metadata:** Refresh runtime metadata whenever `specVersion` changes (currently `21001` on Polkadot, `19000` on Kusama). Update custom pallets (Hyperbridge, FlexibleFee, SALP) in your type registry.
- **Fee estimation:** Run `payment_queryInfo` for vToken transfers; Bifrost’s flexible-fee pallet introduces dynamic surcharge multipliers.
- **Pallet coverage:** Check `rpc_methods` after upgrades to discover new `bifrost_*` runtime APIs (e.g., omnipool analytics, Hyperbridge routing).

## Resources & Tools

- Bifrost network explorer: [bifrost.subscan.io](https://bifrost.subscan.io)
- Bifrost documentation and runtime notes: [docs.bifrost.io](https://docs.bifrost.io/)
- Dwellir Dashboard: [dashboard.dwellir.com/register](https://dashboard.dwellir.com/register)
- Community updates and integration stories: [parachains.info/details/bifrost\_finance\_polkadot](https://parachains.info/details/bifrost_finance_polkadot)

Plan your integration, mint liquidity-backed vTokens, and rely on Dwellir’s globally distributed RPC edge to keep your Bifrost workloads online.

---

## author_pendingExtrinsics - Bifrost RPC Method

# author_pendingExtrinsics - Bifrost RPC Method

Returns all pending extrinsics currently in the transaction pool on Bifrost. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`author_pendingExtrinsics` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Bifrost
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Bifrost transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bifrost/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/bifrost/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/bifrost/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Bifrost RPC Method

# author_rotateKeys - Bifrost RPC Method

Generate a new set of session keys on Bifrost. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`author_rotateKeys` is critical for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Validator Setup** - Generate initial session keys when setting up a new validator on omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Bifrost:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bifrost/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bifrost/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Bifrost RPC Method

# author_submitAndWatchExtrinsic - Bifrost RPC Method

Submits a signed extrinsic to Bifrost and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Bifrost
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bifrost/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bifrost/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/bifrost/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Bifrost RPC Method

# author_submitExtrinsic - Bifrost RPC Method

Submits a fully signed extrinsic to Bifrost for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`author_submitExtrinsic` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Token Transfers** -- Send native tokens or assets between accounts on Bifrost
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bifrost/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/bifrost/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Bifrost RPC Method

# beefy_getFinalizedHead - Bifrost RPC Method

Returns the block hash of the latest BEEFY-finalized block on Bifrost. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`beefy_getFinalizedHead` is important for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/bifrost/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Bifrost RPC Method

# chain_getBlock - Bifrost RPC Method

Retrieves complete block information from Bifrost, including the block header, extrinsics, and justifications.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/bifrost/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/bifrost/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Bifrost RPC Method

# chain_getBlockHash - Bifrost RPC Method

Returns the block hash for a given block number on Bifrost. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`chain_getBlockHash` is fundamental for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Bifrost
- **Block Navigation** - Navigate the blockchain history for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Bifrost
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Bifrost for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Bifrost state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Bifrost network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/bifrost/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Bifrost RPC Method

# chain_getFinalizedHead - Bifrost RPC Method

Returns the hash of the last finalized block on Bifrost. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`chain_getFinalizedHead` is critical for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Bifrost
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Bifrost:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bifrost/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/bifrost/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Bifrost RPC Method

# chain_getHeader - Bifrost RPC Method

Returns the block header for a given hash on Bifrost. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`chain_getHeader` is ideal for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Bifrost
- **Chain Synchronization** - Track block production and monitor chain progress for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Bifrost:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Bifrost chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Bifrost block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bifrost/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Bifrost RPC Method

# chain_subscribeFinalizedHeads - Bifrost RPC Method

Subscribe to receive notifications when blocks are finalized on Bifrost. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Exchange Deposits** - Only credit funds after finalization for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Bifrost:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/bifrost/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Bifrost RPC Method

# chain_subscribeNewHeads - Bifrost RPC Method

Subscribe to receive notifications when new block headers are produced on Bifrost. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`chain_subscribeNewHeads` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Block Monitoring** - Track new blocks in real time on Bifrost for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Bifrost as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Bifrost:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/bifrost/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/bifrost/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Bifrost RPC Method

# grandpa_roundState - Bifrost RPC Method

Returns the state of the current GRANDPA finality round on Bifrost when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`grandpa_roundState` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Bifrost, critical for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/bifrost/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/bifrost/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Bifrost RPC Method

# payment_queryFeeDetails - Bifrost RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Bifrost. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`payment_queryFeeDetails` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Bifrost
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/bifrost/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/bifrost/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bifrost/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/bifrost/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Bifrost RPC Method

# payment_queryInfo - Bifrost RPC Method

Estimates the fee for an encoded extrinsic on Bifrost. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`payment_queryInfo` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Bifrost
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bifrost/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/bifrost/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/bifrost/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bifrost/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Bifrost RPC Method

# rpc_methods - Bifrost RPC Method

Returns a list of all RPC methods exposed by the Bifrost node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`rpc_methods` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Bifrost node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Bifrost endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Bifrost endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bifrost/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bifrost/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Bifrost RPC Method

# state_call - Bifrost RPC Method

Calls a runtime API function on Bifrost and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`state_call` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bifrost/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bifrost/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/bifrost/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) -- Get the node version for compatibility checking

---

## state_getKeys

# state_getKeys

## Description

Returns all storage keys with a given prefix. Use this to discover accounts, vToken positions, or other on-chain items before fetching values with `state_getStorage`.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix
- `blockHash` (`string, optional`): Block hash for historical queries

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Array of matching hex-encoded storage keys.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b6a7c9a35a95a160cb4cad330558dfa56d6f646c755b98a7afd0913860592153322b957be394a0619f20b32679ac1014",
    "0x26aa394eea5630e07c48ae0c9558cef7c8e63e63a001c280f6dc809625f6ce9c53c51e645dd0a2c3e0800a9c53aac6ffe81912f6526f364eb8e4a36c2e304931"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7",
    null
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript

```python
keys = substrate.rpc_request(
    method='state_getKeys',
    params=['0x26aa394eea5630e07c48ae0c9558cef7', None]
)["result"]
print(len(keys))
```

```javascript
const keyPrefix = api.registry.createType('StorageKey', 'System', 'Account').toHex();
const keys = await api.rpc.state.getKeys(keyPrefix, null);
console.log('Found', keys.length, 'System.Account entries');
```

## Tips

- For large datasets prefer `state_getKeysPaged` to avoid stress-testing nodes.
- Combine with Bifrost-specific prefixes (e.g., `Omnipool` or `Farming`) to iterate liquidity pools and reward schedules.

---

## state_getKeysPaged - Bifrost RPC Method

# state_getKeysPaged - Bifrost RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Bifrost. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`state_getKeysPaged` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Bifrost
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bifrost/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bifrost/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Bifrost RPC Method

# state_getMetadata - Bifrost RPC Method

Returns the runtime metadata for Bifrost as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`state_getMetadata` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Bifrost
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Bifrost:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Bifrost:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bifrost/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/bifrost/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Bifrost RPC Method

# state_getRuntimeVersion - Bifrost RPC Method

Returns the runtime version information for Bifrost, including the spec name, spec version, implementation version, and supported API versions.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`state_getRuntimeVersion` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Bifrost
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Bifrost in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bifrost/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Bifrost RPC Method

# state_getStorage - Bifrost RPC Method

Returns the SCALE-encoded storage value for a given key on Bifrost. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`state_getStorage` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Bifrost
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/bifrost/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bifrost/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Bifrost RPC Method

# state_queryStorageAt - Bifrost RPC Method

Queries multiple storage keys at a specific block on Bifrost, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`state_queryStorageAt` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Bifrost
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bifrost/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/bifrost/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/bifrost/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bifrost/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Bifrost RPC Method

# system_chain - Bifrost RPC Method

Returns the chain name of the Bifrost network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`system_chain` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Network Verification** -- Confirm your application is connected to the correct Bifrost network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Bifrost"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', 'Bifrost');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/bifrost/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/bifrost/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bifrost/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/bifrost/rpc_methods) -- List all available RPC methods

---

## system_health - Bifrost RPC Method

# system_health - Bifrost RPC Method

Returns the health status of the Bifrost node, including peer count, sync state, and whether the node expects to have peers.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`system_health` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Bifrost
- **Load Balancing** - Route requests only to healthy, fully synced nodes for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Bifrost:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Bifrost nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/bifrost/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Bifrost RPC Method

# system_name - Bifrost RPC Method

Returns the node implementation name on Bifrost. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`system_name` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Bifrost
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Bifrost node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Bifrost node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Bifrost node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Bifrost node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Bifrost node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Bifrost nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/bifrost/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/bifrost/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bifrost/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/bifrost/rpc_methods) -- List all available RPC methods

---

## system_properties - Bifrost RPC Method

# system_properties - Bifrost RPC Method

Returns the chain-specific properties for Bifrost, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`system_properties` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Bifrost
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bifrost/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bifrost/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bifrost/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/bifrost/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/bifrost/rpc_methods) -- List all available RPC methods

---

## system_version - Bifrost RPC Method

# system_version - Bifrost RPC Method

Returns the node implementation version string on Bifrost. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Bifrost?** Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.

## When to Use This Method

`system_version` is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Bifrost
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Bifrost node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Bifrost node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Bifrost node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Bifrost node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bifrost-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Bifrost node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Bifrost nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bifrost/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bifrost/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/bifrost/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bifrost/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/bifrost/rpc_methods) -- List all available RPC methods

---

## Bittensor - Decentralized Machine Learning Network

# Bittensor - Decentralized Machine Learning Network

## Description

Interact with Substrate JSON‑RPC. This method is commonly used to build reliable indexers, developer tooling, and responsive UIs.

## Bittensor RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Bittensor supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Bittensor?

Bittensor is a revolutionary blockchain that creates a decentralized marketplace for machine learning models and computational intelligence. Built on Substrate, Bittensor enables:

### **AI-Native Blockchain**

- **Decentralized ML** - Train and serve models in a trustless environment
- **Incentivized Intelligence** - Earn TAO tokens for contributing compute and models
- **Collaborative Learning** - Models improve through network-wide collaboration

### **Advanced Capabilities**

- **Neural Mining** - Mine TAO tokens by running AI models
- **36+ Subnets** - Specialized networks for different AI tasks (expanding to 1024)
- **Yuma Consensus** - Novel consensus mechanism for ML validation

### **Innovation Platform**

- **Open AI Marketplace** - Access diverse AI models and services
- **Composable Intelligence** - Build complex AI systems from network primitives
- **Research Network** - Contribute to cutting-edge ML research

## Quick Start with Bittensor

Connect to Bittensor in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Python

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Bittensor mainnet
const provider = new JsonRpcProvider(
  'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Bittensor mainnet
const web3 = new Web3(
  'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Bittensor:', chainId);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```python
from web3 import Web3

# Connect to Bittensor mainnet
w3 = Web3(Web3.HTTPProvider(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Check connection
if w3.is_connected():
    print("Connected to Bittensor")

# Get latest block
latest_block = w3.eth.block_number
print(f"Latest block: {latest_block}")

# Get account balance
balance = w3.eth.get_balance('0x...')
print(f"Balance: {balance} TAO")
```

## Network Information

| Parameter    | Value      | Details         |
| ------------ | ---------- | --------------- |
| Chain ID     | N/A        | Substrate-based |
| Block Time   | 12 seconds | Average         |
| Native Token | TAO        | 21M max supply  |
| Consensus    | Yuma       | ML Validation   |

## API Reference

Bittensor exposes both an Ethereum-compatible JSON-RPC (via Frontier) and native Substrate RPC. Use either or both depending on your integration.

#### Custom RPC Extensions

Bittensor nodes also expose custom RPC namespaces for chain‑specific AI/ML data:

- `subnetInfo_*`: subnet configuration, hyperparameters, metagraphs
- `neuronInfo_*`: neuron and mechagraph data
- `delegateInfo_*`: delegation and delegate details
- `swap_*`: TAO and ALPHA swap simulation helpers

These are implemented by the chain and surfaced over JSON‑RPC; see the runtime and node RPC code for details. Refer to the links in the Resources section below.

## Common Integration Patterns

### **Subnet Interaction**

Connect to Bittensor subnets for specialized AI tasks:

```javascript
// Query subnet information
async function getSubnetInfo(subnetId) {
  const result = await provider.call({
    to: SUBNET_REGISTRY_ADDRESS,
    data: encodeSubnetQuery(subnetId)
  });

  return decodeSubnetInfo(result);
}

// Register as miner
async function registerMiner(subnetId, modelEndpoint) {
  const tx = {
    to: SUBNET_REGISTRY_ADDRESS,
    data: encodeMinerRegistration(subnetId, modelEndpoint),
    value: REGISTRATION_FEE
  };

  const receipt = await signer.sendTransaction(tx);
  return receipt;
}
```

### **TAO Token Operations**

Manage TAO tokens and staking:

```javascript
// Stake TAO tokens
async function stakeTAO(amount, validatorAddress) {
  const stakingContract = new Contract(
    STAKING_CONTRACT_ADDRESS,
    STAKING_ABI,
    signer
  );

  const tx = await stakingContract.stake(
    validatorAddress,
    { value: parseEther(amount) }
  );

  return tx.wait();
}

// Query staking rewards
async function getStakingRewards(address) {
  const rewards = await stakingContract.pendingRewards(address);
  return formatUnits(rewards, 9); // TAO has 9 decimals
}
```

### **Model Validation**

Validate AI model outputs on-chain:

```javascript
// Submit model output for validation
async function submitModelOutput(subnetId, taskId, output) {
  const validationContract = new Contract(
    VALIDATION_CONTRACT_ADDRESS,
    VALIDATION_ABI,
    signer
  );

  const proof = generateProof(output);
  const tx = await validationContract.submitOutput(
    subnetId,
    taskId,
    output,
    proof
  );

  return tx.wait();
}
```

## Performance Best Practices

### 1. **Efficient Querying**

Optimize queries for Bittensor's unique architecture:

```javascript
// Batch subnet queries
async function batchSubnetQueries(subnetIds) {
  const queries = subnetIds.map(id => ({
    to: SUBNET_REGISTRY_ADDRESS,
    data: encodeSubnetQuery(id)
  }));

  const results = await Promise.all(
    queries.map(q => provider.call(q))
  );

  return results.map(decodeSubnetInfo);
}
```

### 2. **Caching Strategy**

Cache frequently accessed subnet and model data:

```javascript
class SubnetCache {
  constructor(ttl = 60000) { // 1 minute TTL
    this.cache = new Map();
    this.ttl = ttl;
  }

  async get(subnetId, fetcher) {
    const key = `subnet_${subnetId}`;
    const cached = this.cache.get(key);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    const data = await fetcher(subnetId);
    this.cache.set(key, { data, timestamp: Date.now() });
    return data;
  }
}
```

### 3. **Connection Management**

Maintain persistent connections for real-time updates:

```javascript
// WebSocket connection for real-time updates
const wsProvider = new WebSocketProvider(
  'wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Subscribe to subnet events
wsProvider.on('subnet_update', (event) => {
  console.log('Subnet updated:', event);
});
```

## Troubleshooting Common Issues

### Error: "Invalid subnet ID"

Ensure you're using valid subnet identifiers:

```javascript
// Validate subnet ID before operations
async function validateSubnet(subnetId) {
  const exists = await provider.call({
    to: SUBNET_REGISTRY_ADDRESS,
    data: encodeSubnetExists(subnetId)
  });

  if (!exists) {
    throw new Error(`Subnet ${subnetId} does not exist`);
  }

  return true;
}
```

### Error: "Insufficient stake"

Check staking requirements before operations:

```javascript
// Check minimum stake requirement
async function checkStakeRequirement(operation) {
  const required = await getMinimumStake(operation);
  const current = await getUserStake(address);

  if (current < required) {
    throw new Error(`Need ${required - current} more TAO staked`);
  }
}
```

## Resources & Tools

### Official Resources

- [Bittensor Documentation](https://docs.bittensor.com)
- [Taostats Explorer](https://taostats.io)
- [Bittensor GitHub](https://github.com/opentensor/bittensor)

### Developer Tools

- [Bittensor SDK](https://pypi.org/project/bittensor/)
- [Subnet Template](https://github.com/opentensor/subnet-template)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Bittensor with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## account_nextIndex - Bittensor RPC Method

# account_nextIndex - Bittensor RPC Method

Returns the next valid transaction index (nonce) for a given account. This is an alias for `system_accountNextIndex` and considers both finalized state and pending transactions in the transaction pool. Using the correct nonce is essential when constructing signed extrinsics -- an incorrect nonce leads to `BadProof`, `Future`, or `Stale` transaction errors.

## Code Examples

## Request Parameters

- `accountId` (`string, required`): The SS58-encoded address or hex-encoded AccountId (32 bytes) of the account to query.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "account_nextIndex",
  "params": [
    "<accountId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`number, required`): The next valid nonce for the account. This accounts for pending transactions in the pool.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Use Cases

- **Transaction construction** -- Get the correct nonce before signing and submitting extrinsics to Bittensor (transfers, staking, subnet operations).
- **Batch transaction submission** -- When sending multiple transactions in sequence, increment the nonce manually starting from this value.
- **Pool-aware nonce** -- Unlike reading the nonce directly from storage, this method accounts for pending (not yet included) transactions in the pool.

## Notes

- This method is an alias for `system_accountNextIndex`. Both return identical results.
- The returned nonce includes pending transactions in the pool. If those transactions are dropped, the nonce may shift.
- For rapid transaction submission, consider manually incrementing nonces rather than querying between each submission.

## Related Methods

- [`system_accountNextIndex`](https://www.dwellir.com/docs/bittensor/system_accountNextIndex) -- Canonical method (same functionality)
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit a signed extrinsic using the nonce
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) -- View pending transactions in the pool
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read the on-chain nonce directly from `System.Account` storage (does not include pool)

---

## archive_v1_body - Bittensor RPC Method

# archive_v1_body - Bittensor RPC Method

Returns the body of a block identified by its hash via the new JSON-RPC v2 archive API. The block body contains the ordered list of extrinsics (transactions, inherents, and unsigned calls) included in that block. This method is part of the `archive` namespace introduced in the new JSON-RPC specification and is designed for clients that need efficient historical data access on Bittensor without maintaining a full follow subscription.

## Code Examples

## Request Parameters

- `hash` (`string, required`): The hex-encoded block hash (e.g. `"0x1e8a..."`) whose body to retrieve.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_body",
  "params": [
    "<hash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array | null, required`): Array of hex-encoded SCALE extrinsics included in the block, in execution order. `null` if the block hash cannot be resolved.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Indexers and explorers** -- Retrieve all extrinsics in a historical block for indexing transfers, staking operations, and subnet registrations on Bittensor.
- **Analytics pipelines** -- Extract historical transaction data across block ranges without replaying the chain. Combine with `archive_v1_hashByHeight` to iterate blocks sequentially.
- **Audit tooling** -- Verify the contents of specific blocks during forensic analysis of on-chain activity.
- **Subnet monitoring** -- Examine historical blocks for subnet registration, weight-setting, and staking extrinsics to analyze Bittensor network behavior over time.

## Bittensor Context

On Bittensor, block bodies contain Substrate extrinsics that encode TAO transfers, subnet operations (`register`, `set_weights`, `add_stake`, `remove_stake`), and governance actions. Each extrinsic is SCALE-encoded and must be decoded using the runtime metadata from the same block era.

## Notes

- This method is part of the new JSON-RPC v2 specification and may not be available on all node configurations.
- On public shared RPC endpoints the archive namespace may be disabled or rate-limited.
- For real-time block body access, consider using `chainHead_v1_body` within a follow subscription instead.

## Related Methods

- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Get the header for a historical block
- [`archive_v1_call`](https://www.dwellir.com/docs/bittensor/archive_v1_call) -- Execute a runtime call against historical state
- [`archive_v1_hashByHeight`](https://www.dwellir.com/docs/bittensor/archive_v1_hashByHeight) -- Resolve a block height to a hash before querying its body
- [`chainHead_v1_body`](https://www.dwellir.com/docs/bittensor/chainHead_v1_body) -- Get block body within a follow subscription
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) -- Legacy method to retrieve a full block (header + body)

---

## archive_v1_call - Bittensor RPC Method

# archive_v1_call - Bittensor RPC Method

Executes a runtime API call against the state of a specific historical block via the new JSON-RPC v2 archive API. This allows you to invoke any runtime API function (such as `Metadata_metadata`, `AccountNonceApi_account_nonce`, or `TransactionPaymentApi_query_info`) using the state as it existed at a given block, without needing an active follow subscription.

## Code Examples

## Request Parameters

- `hash` (`string, required`): Hex-encoded block hash identifying which historical state to query against.
- `function` (`string, required`): The runtime API function name (e.g. `"Metadata_metadata"`).
- `callParameters` (`string, required`): Hex-encoded SCALE-encoded call parameters. Use `"0x"` when the function takes no arguments.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_call",
  "params": [
    "<hash>",
    "<function>",
    "<callParameters>"
  ],
  "id": 1
}
```

## Response Fields

- `result.success` (`boolean, required`): `true` when the runtime call executed successfully
- `result.value` (`string, required`): Hex-encoded SCALE output returned by the runtime API when `success` is `true`
- `result.error` (`string, required`): Error string returned by the runtime when `success` is `false`

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "result.success": true,
    "result.value": "<value>",
    "result.error": "<value>"
  }
}
```

## Use Cases

- **Historical metadata retrieval** -- Fetch the runtime metadata as it was at a past block to correctly decode storage and extrinsics from that era.
- **Fee estimation on past state** -- Call `TransactionPaymentApi_query_info` against historical state to understand fee structures at a given block.
- **Cross-version analytics** -- Compare runtime API outputs across different blocks to track how Bittensor subnet parameters evolved over time.

## Bittensor Context

On Bittensor, runtime APIs can expose subnet-specific data, neuron metadata, and staking information. By calling these APIs at historical blocks, you can reconstruct how subnet parameters, validator weights, and incentive mechanisms evolved over time -- essential for research and analytics on the decentralized AI network.

## Notes

- This is part of the new JSON-RPC v2 specification. Availability depends on node configuration and the archive namespace being enabled.
- The `callParameters` must be SCALE-encoded. Use a library such as `@polkadot/types` or `parity-scale-codec` to encode them.
- On public shared RPC endpoints, this method may be disabled or rate-limited.

## Related Methods

- [`archive_v1_body`](https://www.dwellir.com/docs/bittensor/archive_v1_body) -- Get the block body from the archive
- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Get the block header from the archive
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Legacy runtime API call (at latest or specific block)
- [`state_callAt`](https://www.dwellir.com/docs/bittensor/state_callAt) -- Legacy runtime API call at a specific block hash
- [`chainHead_v1_call`](https://www.dwellir.com/docs/bittensor/chainHead_v1_call) -- Runtime call within a follow subscription

---

## archive_v1_finalizedHeight - Bittensor RPC Method

# archive_v1_finalizedHeight - Bittensor RPC Method

Returns the height (block number) of the highest finalized block known to the archive node. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget. This method provides a quick way to determine how far the finalized chain has progressed without needing to resolve block hashes.

zed block. |

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_finalizedHeight",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`number, required`): The block number of the latest finalized block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Use Cases

- **Indexer checkpoints** -- Determine the safe finalized height before committing indexed data to your database. Only data at or below this height is guaranteed immutable.
- **Sync progress monitoring** -- Compare the finalized height against the latest best block to gauge how far behind finalization is.
- **Data pipeline boundaries** -- Set upper bounds on block ranges for batch processing, ensuring you only process finalized blocks for analytics on Bittensor subnet activity.
- **Safe state queries** -- Use the finalized height to derive a block hash (via `archive_v1_hashByHeight`) and then query storage at that hash, ensuring the state you read cannot be reverted.

## Bittensor Context

Bittensor uses GRANDPA for deterministic finality. Once a block is finalized, all extrinsics in it (TAO transfers, subnet registrations, weight updates, staking operations) are permanently committed. Indexers and analytics tools should only treat data as authoritative after finalization.

## Notes

- This method is part of the new JSON-RPC v2 specification and may not be enabled on all Bittensor nodes.
- The finalized height increases monotonically and should never decrease.
- On public shared RPC endpoints the archive namespace may be disabled or rate-limited.

## Related Methods

- [`archive_v1_hashByHeight`](https://www.dwellir.com/docs/bittensor/archive_v1_hashByHeight) -- Convert the finalized height to a block hash
- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Fetch the header at the finalized height
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) -- Legacy method returning the finalized block hash
- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Follow the chain head including finality notifications

---

## archive_v1_genesisHash - Bittensor RPC Method

# archive_v1_genesisHash - Bittensor RPC Method

Returns the hash of the genesis block (block 0) as reported by the archive node. The genesis hash uniquely identifies a Substrate-based chain and is commonly used to verify that a client is connected to the correct network. On Bittensor mainnet the genesis hash is a fixed value that never changes.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_genesisHash",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded 32-byte blake2b hash of the genesis block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Network verification** -- Confirm you are connected to Bittensor mainnet (and not a testnet or fork) by comparing the genesis hash against a known value.
- **Transaction signing** -- The genesis hash is required when constructing the signed payload for Substrate extrinsics; using the wrong value causes signature verification to fail.
- **Multi-chain applications** -- Identify which chain a connection belongs to in applications that connect to multiple Substrate networks.

## Bittensor Context

The Bittensor mainnet genesis hash uniquely identifies the network. It is embedded in every signed extrinsic's "signed extensions" payload, binding transactions to the correct chain. If you sign a transaction with the wrong genesis hash, it will be rejected with a `BadProof` error. The genesis hash also distinguishes Bittensor mainnet from testnets and local dev chains.

## Notes

- This method is part of the new JSON-RPC v2 specification. It mirrors `chainSpec_v1_genesisHash` and the legacy `chain_getBlockHash(0)`.
- The genesis hash is immutable for a given chain and can be safely cached.
- On public shared RPC endpoints the archive namespace may be disabled.

## Related Methods

- [`chainSpec_v1_genesisHash`](https://www.dwellir.com/docs/bittensor/chainSpec_v1_genesisHash) -- Get genesis hash via the chainSpec namespace
- [`archive_v1_hashByHeight`](https://www.dwellir.com/docs/bittensor/archive_v1_hashByHeight) -- Get the hash for any block height (use height 0 for genesis)
- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Get the genesis block header
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) -- Legacy method to get a block hash by number

---

## archive_v1_hashByHeight - Bittensor RPC Method

# archive_v1_hashByHeight - Bittensor RPC Method

Returns the block hash for a given block height (number) via the new JSON-RPC v2 archive API. Because Substrate chains can have forks, a single height may correspond to more than one block hash on non-finalized parts of the chain. For finalized blocks there is always exactly one hash per height.

zed blocks; may contain multiple for non-finalized forks. Returns an empty array if the height is beyond the chain tip. |

## Code Examples

## Request Parameters

- `height` (`number, required`): The block number (height) to look up.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_hashByHeight",
  "params": [
    "<height>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded block hashes at the given height. Typically one element for finalized blocks; may contain multiple for non-finalized forks. Returns an empty array if the height is beyond the chain tip.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Block resolution** -- Resolve a block number to a hash before querying `archive_v1_body`, `archive_v1_header`, or `archive_v1_call`.
- **Sequential block scanning** -- Iterate through blocks by height for indexing pipelines, converting each height to a hash before fetching block contents.
- **Fork detection** -- Identify forks by checking whether a height returns multiple hashes on the non-finalized chain.

## Notes

- This method is part of the new JSON-RPC v2 specification and may not be available on all node configurations.
- Heights beyond the finalized tip may return multiple hashes due to chain forks.
- On public shared RPC endpoints the archive namespace may be disabled or rate-limited.

## Related Methods

- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Get the header once you have a block hash
- [`archive_v1_body`](https://www.dwellir.com/docs/bittensor/archive_v1_body) -- Get the block body once you have a block hash
- [`archive_v1_finalizedHeight`](https://www.dwellir.com/docs/bittensor/archive_v1_finalizedHeight) -- Get the latest finalized height
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) -- Legacy method to resolve block number to hash

---

## archive_v1_header - Bittensor RPC Method

# archive_v1_header - Bittensor RPC Method

Returns the header of a block identified by its hash via the new JSON-RPC v2 archive API. The header contains the parent hash, block number, state root, extrinsics root, and digest (which includes consensus-related log items such as BABE slot info and GRANDPA authority changes). This is a lightweight way to inspect block metadata without fetching the full body.

## Code Examples

## Request Parameters

- `hash` (`string, required`): Hex-encoded block hash to retrieve the header for.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_header",
  "params": [
    "<hash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string | null, required`): Hex-encoded SCALE-encoded Substrate header for the requested block. `null` if the block hash cannot be resolved.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Chain traversal** -- Walk the chain backwards by following `parentHash` links from header to header.
- **Light client verification** -- Verify block headers and state roots without downloading the full block body.
- **Indexer metadata** -- Extract block numbers, timestamps (from digest), and state roots for indexed block records.

## Notes

- This method is part of the new JSON-RPC v2 specification and may not be enabled on all Bittensor nodes.
- The header is significantly smaller than a full block, making it ideal for lightweight monitoring.
- On public shared RPC endpoints the archive namespace may be disabled or rate-limited.

## Related Methods

- [`archive_v1_body`](https://www.dwellir.com/docs/bittensor/archive_v1_body) -- Get the block body (extrinsics) for the same hash
- [`archive_v1_hashByHeight`](https://www.dwellir.com/docs/bittensor/archive_v1_hashByHeight) -- Resolve a block height to a hash
- [`archive_v1_call`](https://www.dwellir.com/docs/bittensor/archive_v1_call) -- Execute a runtime call at the same block's state
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) -- Legacy method to fetch a block header
- [`chainHead_v1_header`](https://www.dwellir.com/docs/bittensor/chainHead_v1_header) -- Get header within a follow subscription

---

## archive_v1_stopStorage - Bittensor RPC Method

# archive_v1_stopStorage - Bittensor RPC Method

Stops an active storage query operation that was previously started via the archive API. When you initiate a storage query through the archive namespace over a WebSocket connection, the node begins streaming results. Call this method to cancel that operation before it completes, freeing server-side resources.

## Code Examples

## Request Parameters

- `subscriptionId` (`string, required`): The subscription or operation ID returned when the storage query was started.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_stopStorage",
  "params": [
    "<subscriptionId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`boolean, required`): Indicates whether the storage operation was successfully stopped on the shared endpoint.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Resource cleanup** -- Stop a long-running storage stream when you have received enough data, preventing unnecessary load on the node.
- **Error recovery** -- Cancel a stalled or slow storage query and retry with different parameters.
- **Graceful shutdown** -- Clean up active subscriptions before disconnecting your WebSocket client.

## Notes

- This method is part of the new JSON-RPC v2 specification and operates over WebSocket connections.
- Always stop subscriptions you no longer need to avoid leaking server resources.
- On public shared RPC endpoints the archive namespace may be disabled.

## Related Methods

- [`archive_v1_storageDiff`](https://www.dwellir.com/docs/bittensor/archive_v1_storageDiff) -- Stream storage changes between blocks (stopped with `archive_v1_storageDiff_stopStorageDiff`)
- [`archive_v1_body`](https://www.dwellir.com/docs/bittensor/archive_v1_body) -- Get block body from the archive
- [`chainHead_v1_stopOperation`](https://www.dwellir.com/docs/bittensor/chainHead_v1_stopOperation) -- Stop a follow-based operation
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop following the chain head

---

## archive_v1_storage - JSON-RPC Method

# archive_v1_storage - JSON-RPC Method

## Description

Query historical blocks, storage, and diffs via the archive service. Build fast historical analytics without re‑executing the chain.

Starts an archive storage operation for the requested block hash and storage queries.
The call returns an opaque operation ID immediately, then streams matching
`archive_v1_storageEvent` notifications over the same WebSocket connection.

## Code Examples

## Request Parameters

- `hash` (`string, required`): Hex-encoded block hash whose archived storage you want to inspect.
- `items` (`array<object>, required`): One or more storage queries describing the key and lookup type to fetch from archive storage.
- `childTrie` (`string | null, optional`): Child trie key for default-namespace child storage lookups. Use `null` for main storage.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_storage",
  "params": [
    "<blockHash>",
    [
      {
        "key": "0x3a636f6465",
        "type": "value"
      }
    ],
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Opaque operation ID. Read the requested storage items from subsequent `archive_v1_storageEvent` notifications on the same connection.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<operationId>"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

---

## archive_v1_storageDiff - Bittensor RPC Method

# archive_v1_storageDiff - Bittensor RPC Method

Streams the differences in storage between two blocks via the new JSON-RPC v2 archive API. This method reports which storage keys were added, modified, or deleted between a previous block and a target block. It is designed for efficient state synchronization and change tracking without downloading full storage snapshots.

## Code Examples

## Request Parameters

- `hash` (`string, required`): Hex-encoded hash of the target block (the newer block).
- `items` (`array, required`): Array of storage query items specifying which keys or prefixes to watch for changes.
- `previousHash` (`string, optional`): Hex-encoded hash of the previous block to diff against. Defaults to the parent block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_storageDiff",
  "params": [
    "<hash>",
    "<items>",
    "<previousHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The direct RPC response is a subscription/operation ID string. Results then arrive as `archive_v1_storageDiffEvent` notifications over the same WebSocket connection: | Event | Description | |-------|-------------| | `storageDiff` | A batch of changed keys and returned values or hashes | | `storageDiffError` | An error was encountered while streaming diff results | | `storageDiffDone` | The diff stream has completed |

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Use Cases

- **Incremental indexing** -- Detect only the storage keys that changed between blocks, dramatically reducing the amount of data an indexer needs to process.
- **State sync** -- Efficiently synchronize a local state mirror by applying only the diffs instead of re-reading entire storage.
- **Change auditing** -- Track changes to specific storage maps (e.g. Bittensor subnet parameters, staking ledgers) between two points in time.

## Notes

- This method is part of the new JSON-RPC v2 specification and requires a WebSocket connection for streaming results.
- Use `archive_v1_storageDiff_stopStorageDiff` to cancel an in-progress diff operation.
- On public shared RPC endpoints the archive namespace may be disabled or rate-limited.

## Related Methods

- [`archive_v1_storageDiff_stopStorageDiff`](https://www.dwellir.com/docs/bittensor/archive_v1_storageDiff_stopStorageDiff) -- Stop an active storage diff stream
- [`archive_v1_body`](https://www.dwellir.com/docs/bittensor/archive_v1_body) -- Get the block body for context around changes
- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Get the block header for the diffed blocks
- [`state_queryStorage`](https://www.dwellir.com/docs/bittensor/state_queryStorage) -- Legacy method to query storage changes over a block range
- [`chainHead_v1_storage`](https://www.dwellir.com/docs/bittensor/chainHead_v1_storage) -- Query storage within a follow subscription

---

## archive_v1_storageDiff_stopStorageDiff - Bittensor RPC Method

# archive_v1_storageDiff_stopStorageDiff - Bittensor RPC Method

Stops an active storage diff operation that was previously started with `archive_v1_storageDiff`. When a storage diff is streaming results over WebSocket, this method cancels the operation and frees server-side resources. Always call this when you no longer need the diff results to avoid unnecessary load on the node.

## Code Examples

## Request Parameters

- `subscriptionId` (`string, required`): The subscription or operation ID returned when the storage diff was started.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "archive_v1_storageDiff_stopStorageDiff",
  "params": [
    "<subscriptionId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`boolean, required`): Indicates whether the storage diff operation was successfully stopped on the shared endpoint.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Resource cleanup** -- Cancel a long-running diff operation once you have collected the changes you need.
- **Error recovery** -- Stop a stalled diff and retry with adjusted parameters (e.g. a narrower key prefix or smaller block range).
- **Graceful shutdown** -- Clean up all active diff subscriptions before disconnecting your WebSocket client.

## Notes

- This method is part of the new JSON-RPC v2 specification and operates over WebSocket connections.
- Always stop diff subscriptions you no longer need. Leaked subscriptions consume memory and bandwidth on the server.
- On public shared RPC endpoints the archive namespace may be disabled.

## Related Methods

- [`archive_v1_storageDiff`](https://www.dwellir.com/docs/bittensor/archive_v1_storageDiff) -- Start a storage diff stream between two blocks
- [`archive_v1_stopStorage`](https://www.dwellir.com/docs/bittensor/archive_v1_stopStorage) -- Stop a regular storage query operation
- [`chainHead_v1_stopOperation`](https://www.dwellir.com/docs/bittensor/chainHead_v1_stopOperation) -- Stop a follow-based operation
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop following the chain head entirely

---

## author_hasKey - Bittensor RPC Method

# author_hasKey - Bittensor RPC Method

Checks whether the node's keystore contains a given public key for a specified key type. This is an administrative method used to verify that a validator or collator node has the correct session keys loaded before participating in block production or consensus. It is typically disabled on public shared RPC endpoints.

## Code Examples

## Request Parameters

- `publicKey` (`string, required`): Hex-encoded public key to look up (e.g. `"0xd43593..."`)
- `keyType` (`string, required`): Four-character key type identifier (e.g. `"babe"`, `"gran"`, `"aura"`, `"imon"`)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_hasKey",
  "params": [
    "<publicKey>",
    "<keyType>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`boolean, required`): `true` if the key exists in the keystore for the given type, `false` otherwise.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Validator setup verification** -- Confirm that session keys are properly loaded in the keystore before a validator begins producing blocks.
- **Key rotation checks** -- After rotating session keys with `author_rotateKeys`, verify the new keys are present.
- **Monitoring and alerts** -- Automated health checks to ensure a validator node still has the required keys.

## Notes

- This is an unsafe/administrative RPC method. It must be explicitly enabled on the node with the `--rpc-methods unsafe` flag.
- On Dwellir's shared public RPC endpoints, expect this method to return an error.
- The key type is a 4-byte ASCII identifier corresponding to the consensus or session module that uses the key.

## Related Methods

- [`author_rotateKeys`](https://www.dwellir.com/docs/bittensor/author_rotateKeys) -- Generate new session keys in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit extrinsics (requires keys for signing)
- [`system_nodeRoles`](https://www.dwellir.com/docs/bittensor/system_nodeRoles) -- Check what roles the node is configured with (authority, full, etc.)

---

## author_pendingExtrinsics - Bittensor RPC Method

# author_pendingExtrinsics - Bittensor RPC Method

Returns all pending extrinsics currently in the transaction pool on Bittensor. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`author_pendingExtrinsics` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Bittensor
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Bittensor transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/bittensor/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Bittensor RPC Method

# author_rotateKeys - Bittensor RPC Method

Generate a new set of session keys on Bittensor. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`author_rotateKeys` is critical for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Validator Setup** - Generate initial session keys when setting up a new validator on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Bittensor:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Bittensor RPC Method

# author_submitAndWatchExtrinsic - Bittensor RPC Method

Submits a signed extrinsic to Bittensor and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Bittensor
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- [`system_accountNextIndex`](https://www.dwellir.com/docs/bittensor/system_accountNextIndex) -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/bittensor/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Bittensor RPC Method

# author_submitExtrinsic - Bittensor RPC Method

Submits a fully signed extrinsic to Bittensor for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`author_submitExtrinsic` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Token Transfers** -- Send native tokens or assets between accounts on Bittensor
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/bittensor/payment_queryInfo) -- Estimate fees before submitting
- [`system_accountNextIndex`](https://www.dwellir.com/docs/bittensor/system_accountNextIndex) -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Bittensor RPC Method

# beefy_getFinalizedHead - Bittensor RPC Method

Returns the block hash of the latest BEEFY-finalized block on Bittensor. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`beefy_getFinalizedHead` is not currently exposed on Dwellir's public Bittensor RPC. Use finalized-block signals from supported chain-RPC methods instead.

- **Finalized head reads** — Use `chain_getFinalizedHead` for the current finalized block hash
- **Realtime finalized updates** — Subscribe to `chain_subscribeFinalizedHeads` for push updates

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'

# Response:
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": { "code": -32601, "message": "Method not found" }
}
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const result = await api.rpc.beefy.getFinalizedHead();
  console.log('Unexpected result:', result.toString());
} catch (error) {
  console.log('beefy_getFinalizedHead unsupported:', error.message);
}

await api.disconnect();
```

```python
import requests

response = requests.post(
  'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
  json={
    'jsonrpc': '2.0',
    'method': 'beefy_getFinalizedHead',
    'params': [],
    'id': 1,
  },
)

print(response.json())
# {'error': {'code': -32601, 'message': 'Method not found'}}
```

## Alternative Monitoring Patterns on Bittensor

Because Bittensor does not expose `beefy_getFinalizedHead` on this shared surface, use these finalized-block signals instead.

### 1. Check latest finalized hash directly

Use `chain_getFinalizedHead` for a simple on-demand read of finalized head:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://...');
const api = await ApiPromise.create({ provider });

const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block:', finalizedHash.toHex());
```

### 2. Stream finalized heads

Use `chain_subscribeFinalizedHeads` when you need push-based finalized updates for downstream systems.

```javascript
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number.toString()}: ${header.hash.toHex()}`);
});
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/bittensor/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Bittensor RPC Method

# chain_getBlock - Bittensor RPC Method

Retrieves complete block information from Bittensor, including the block header, extrinsics, and justifications.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x2f0555cc76fc2840a25a6f3a0f0e6d0b1a6dd2e0cecc9e4c2e9e6f3a8d2e5c1b"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x2f0555cc76fc2840a25a6f3a0f0e6d0b1a6dd2e0cecc9e4c2e9e6f3a8d2e5c1b"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x2f0555cc76fc2840a25a6f3a0f0e6d0b1a6dd2e0cecc9e4c2e9e6f3a8d2e5c1b';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x2f0555cc76fc2840a25a6f3a0f0e6d0b1a6dd2e0cecc9e4c2e9e6f3a8d2e5c1b')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Bittensor RPC Method

# chain_getBlockHash - Bittensor RPC Method

Returns the block hash for a given block number on Bittensor. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`chain_getBlockHash` is fundamental for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Bittensor
- **Block Navigation** - Navigate the blockchain history for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Bittensor
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Bittensor for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Bittensor state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Bittensor network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Bittensor RPC Method

# chain_getFinalizedHead - Bittensor RPC Method

Returns the hash of the last finalized block on Bittensor. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`chain_getFinalizedHead` is critical for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Bittensor
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Bittensor:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/bittensor/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHead - JSON-RPC Method

# chain_getHead - JSON-RPC Method

## Description

Return the best (non-finalized) block hash. Use for low‑latency reads when finality is not required.

Returns the block hash of the current best block (not necessarily finalized).

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded best-block hash from the current non-finalized head.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x7d3f644499bb7478ff9e1ae7eab08eb17426d59ebceebbeadcceabd5f985a15e"
}
```

---

## chain_getHeader - Bittensor RPC Method

# chain_getHeader - Bittensor RPC Method

Returns the block header for a given hash on Bittensor. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`chain_getHeader` is ideal for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Bittensor
- **Chain Synchronization** - Track block production and monitor chain progress for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Bittensor:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Bittensor chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Bittensor block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_getRuntimeVersion - JSON-RPC Method

# chain_getRuntimeVersion - JSON-RPC Method

Returns the current runtime specification and transaction version for the node. As a developer, you use this to:

- Detect runtime upgrades and adjust clients accordingly (e.g., refresh metadata).
- Ensure your transaction building/signing logic matches the node’s transactionVersion.
- Gate feature flags or migrations based on specName/specVersion (e.g., API changes between releases).

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`string, required`): Runtime specification name.
- `implName` (`string, required`): Runtime implementation name.
- `authoringVersion` (`number, required`): Authoring version used for block production.
- `specVersion` (`number, required`): Runtime specification version.
- `implVersion` (`number, required`): Implementation version for the node runtime.
- `transactionVersion` (`number, optional`): Transaction format version used when signing extrinsics.
- `stateVersion` (`number, optional`): State trie version exposed by the runtime.
- `apis` (`array, required`): Supported runtime API IDs with their versions.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "node-subtensor",
    "implName": "node-subtensor",
    "authoringVersion": 1,
    "specVersion": 377,
    "implVersion": 1,
    "transactionVersion": 0,
    "stateVersion": 1,
    "apis": [
      [
        "0xdf6acb689907609b",
        5
      ]
    ]
  }
}
```

---

## chain_subscribeAllHeads - JSON-RPC Method

# chain_subscribeAllHeads - JSON-RPC Method

Subscribes to every imported block header over a WebSocket connection, including non-finalized fork heads. This is useful when you need the earliest possible view of block production rather than only finalized chain state.

The initial JSON-RPC response returns a subscription ID. Header payloads are delivered afterward as WebSocket notifications for that subscription.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_subscribeAllHeads",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`string, required`): Subscription ID returned by the node. Subsequent WebSocket notifications carry imported header payloads for this subscription.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_subscribeAllHeads",
    "params": [],
    "id": 1
  }'
```

### JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const api = await ApiPromise.create({
  provider: new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
});

const unsub = await api.rpc.chain.subscribeAllHeads((header) => {
  console.log(`Imported block #${header.number}`);
  console.log(`Hash: ${header.hash?.toHex?.() ?? 'notification header'}`);
});

// Later: unsub();
```

## Use Cases

- **Fork-aware indexers** -- Process every imported head, including temporary forks, before finalization settles.
- **Latency-sensitive monitoring** -- React to new blocks as soon as they are imported by the node.
- **Chain analytics** -- Observe short-lived fork activity or competing block candidates during periods of network churn.

## Notes

- This subscription emits more updates than `chain_subscribeNewHeads` because it includes non-finalized heads.
- Cancel the subscription with `chain_unsubscribeAllHeads` when you no longer need updates.
- Use `chain_subscribeFinalizedHeads` if your workflow only cares about finalized blocks.

## Related Methods

- [`chain_unsubscribeAllHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeAllHeads) -- Cancel this subscription
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Subscribe to canonical new heads
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) -- Subscribe to finalized heads only

---

## chain_subscribeFinalizedHeads - Bittensor RPC Method

# chain_subscribeFinalizedHeads - Bittensor RPC Method

Subscribe to receive notifications when blocks are finalized on Bittensor. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Exchange Deposits** - Only credit funds after finalization for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Bittensor:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/bittensor/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Bittensor RPC Method

# chain_subscribeNewHeads - Bittensor RPC Method

Subscribe to receive notifications when new block headers are produced on Bittensor. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`chain_subscribeNewHeads` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Block Monitoring** - Track new blocks in real time on Bittensor for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Bittensor as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Bittensor:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) - Get full block data with extrinsics
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) - Unsubscribe from new heads

---

## chain_subscribeRuntimeVersion - Bittensor RPC Method

# chain_subscribeRuntimeVersion - Bittensor RPC Method

Subscribes to runtime version changes over a WebSocket connection. Each time the Bittensor runtime is upgraded, this subscription emits a notification containing the new runtime version details. This allows applications to detect upgrades in real time and update their type registries, metadata, and decoders accordingly.

The initial JSON-RPC response returns a subscription ID. Runtime version objects are delivered afterward as WebSocket notifications on that subscription.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_subscribeRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `specName` (`string, required`): Runtime specification name (e.g. `"node-subtensor"`)
- `implName` (`string, required`): Implementation name
- `specVersion` (`number, required`): Specification version number; increments with each runtime upgrade
- `implVersion` (`number, required`): Implementation version
- `transactionVersion` (`number, required`): Transaction format version; changes indicate breaking extrinsic format changes
- `apis` (`array, required`): List of supported runtime API versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_subscribeRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

### JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const api = await ApiPromise.create({
  provider: new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
});

const unsub = await api.rpc.chain.subscribeRuntimeVersion((version) => {
  console.log(`Runtime upgrade detected: specVersion=${version.specVersion}`);
  console.log(`Transaction version: ${version.transactionVersion}`);
});

// Later: unsub();
```

## Use Cases

- **Runtime upgrade detection** -- React to runtime upgrades by refreshing metadata and type registries so your application can decode new extrinsic and storage formats.
- **Indexer maintenance** -- Pause or restart indexing pipelines when a runtime upgrade changes storage layouts or extrinsic formats.
- **Dashboard alerts** -- Display notifications to operators when the Bittensor runtime version changes.

## Notes

- The first notification is emitted immediately with the current runtime version.
- Cancel the subscription with `chain_unsubscribeRuntimeVersion` when no longer needed.
- The `transactionVersion` field is critical: if it changes, previously constructed unsigned extrinsics may no longer be valid.

## Related Methods

- [`chain_unsubscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeRuntimeVersion) -- Cancel this subscription
- [`state_subscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_subscribeRuntimeVersion) -- Equivalent subscription via the state namespace
- [`chain_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_getRuntimeVersion) -- One-shot query for current runtime version
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get the full runtime metadata after detecting an upgrade

---

## chain_unsubscribeAllHeads - Bittensor RPC Method

# chain_unsubscribeAllHeads - Bittensor RPC Method

Cancels a WebSocket subscription that was started with `chain_subscribeAllHeads`. Provide the numeric subscription ID that was returned when the subscription was created. After calling this method, no further block header notifications will be delivered for that subscription.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `chain_subscribeAllHeads`.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeAllHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the subscription ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeAllHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Subscription cleanup** -- Cancel the all-heads subscription when your application no longer needs to track every imported block header.
- **Resource management** -- Prevent server-side resource leaks by unsubscribing before disconnecting from the WebSocket.
- **Subscription rotation** -- Stop an existing subscription before starting a new one with different parameters.

## Notes

- Always unsubscribe when you are done to free server-side resources. This is especially important for long-running applications.
- If the WebSocket connection is dropped, the server automatically cleans up subscriptions, but explicit unsubscription is still best practice.
- This is a WebSocket-only method; it cannot be called over HTTP.
- In Dwellir-hosted Bittensor environments, this call path currently returns `-32603 Internal error` when called directly; close and re-establish the WebSocket session to clear stale subscriptions when needed.

## Related Methods

- [`chain_subscribeAllHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeAllHeads) -- Start the subscription this method cancels
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Cancel a best-block header subscription
- [`chain_unsubscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeFinalizedHeads) -- Cancel a finalized header subscription
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop a v2 chain head follow subscription

---

## chain_unsubscribeFinalisedHeads - Bittensor RPC Method

# chain_unsubscribeFinalisedHeads - Bittensor RPC Method

Cancels a WebSocket subscription that was started with `chain_subscribeFinalisedHeads` (British spelling). This is a legacy alias for `chain_unsubscribeFinalizedHeads` and is functionally identical. Provide the subscription ID returned when the subscription was created.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by the subscribe call.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeFinalisedHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeFinalisedHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Legacy client support** -- Used by older clients or libraries that use British spelling (`Finalised` vs `Finalized`).
- **Subscription cleanup** -- Cancel a finalized-heads subscription when you no longer need finality notifications.

## Notes

- This is a British spelling alias. Modern clients should use `chain_unsubscribeFinalizedHeads`.
- Always unsubscribe when done to prevent server-side resource leaks.
- WebSocket-only; cannot be called over HTTP.

## Related Methods

- [`chain_unsubscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeFinalizedHeads) -- Canonical (American spelling) form
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) -- Start a finalized-heads subscription
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Cancel a best-block header subscription
- [`chain_unsubscribeAllHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeAllHeads) -- Cancel an all-heads subscription

---

## chain_unsubscribeFinalizedHeads - Bittensor RPC Method

# chain_unsubscribeFinalizedHeads - Bittensor RPC Method

Cancels a WebSocket subscription that was started with `chain_subscribeFinalizedHeads`. After calling this method, no further finalized block header notifications will be delivered for that subscription. Provide the numeric subscription ID that was returned when the subscription was created.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `chain_subscribeFinalizedHeads`.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeFinalizedHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeFinalizedHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Subscription cleanup** -- Cancel the finalized-heads subscription when your application (indexer, dashboard, alerting system) no longer needs finality notifications.
- **Resource management** -- Prevent server-side resource leaks in long-running WebSocket applications.
- **Subscription rotation** -- Stop one subscription before starting a fresh one after reconnection or reconfiguration.

## Notes

- Always unsubscribe when done. Even though the server cleans up on disconnect, explicit unsubscription is best practice.
- The British spelling alias `chain_unsubscribeFinalisedHeads` is also available and functionally identical.
- WebSocket-only; cannot be called over HTTP.

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) -- Start the finalized-heads subscription
- [`chain_unsubscribeFinalisedHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeFinalisedHeads) -- British spelling alias
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Cancel a best-block header subscription
- [`chain_unsubscribeAllHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeAllHeads) -- Cancel an all-heads subscription
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop a v2 chain head follow subscription

---

## chain_unsubscribeNewHead - Bittensor RPC Method

# chain_unsubscribeNewHead - Bittensor RPC Method

Cancels a WebSocket subscription that was started with `chain_subscribeNewHead` (singular form, a legacy alias). This is functionally identical to `chain_unsubscribeNewHeads` and exists for backward compatibility. Provide the subscription ID returned when the subscription was created.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by the subscribe call.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeNewHead",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeNewHead",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Legacy client support** -- Used by older clients or libraries that reference the singular form of the method name.
- **Subscription cleanup** -- Cancel a new-head subscription when you no longer need real-time block notifications.

## Notes

- This is a legacy alias. Modern clients should use `chain_unsubscribeNewHeads` (plural).
- Always unsubscribe when you are done to free server-side resources.
- WebSocket-only; cannot be called over HTTP.

## Related Methods

- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Canonical (plural) form of this method
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Start a new-head subscription
- [`chain_unsubscribeAllHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeAllHeads) -- Cancel an all-heads subscription
- [`chain_unsubscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeFinalizedHeads) -- Cancel a finalized-heads subscription

---

## chain_unsubscribeNewHeads - JSON-RPC Method

# chain_unsubscribeNewHeads - JSON-RPC Method

Cancels a WebSocket subscription that was created with `chain_subscribeNewHeads`. Pass the subscription ID you received from the original call.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `chain_subscribeNewHeads`.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeNewHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the subscription ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeNewHeads",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Subscription cleanup** -- Stop receiving new-head notifications when a consumer shuts down.
- **Resource management** -- Release server-side subscription state in long-running dashboards or indexers.

## Notes

- Use the subscription ID returned by `chain_subscribeNewHeads`.
- Valid active subscription IDs return `true`. Invalid or already-closed IDs return `false`.
- This method is only available over WebSocket.
- In Dwellir-hosted Bittensor environments, unsubscribing this way can return `-32603 Internal error` after a successful subscription flow test; if cleanup is required, close the WebSocket connection to release session state.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Start a new-head subscription
- [`chain_unsubscribeNewHead`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHead) -- Legacy singular alias
- [`chain_unsubscribeAllHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeAllHeads) -- Cancel an all-heads subscription

---

## chain_unsubscribeRuntimeVersion - JSON-RPC...

# chain_unsubscribeRuntimeVersion - JSON-RPC...

Cancels a runtime-version subscription that was created with `chain_subscribeRuntimeVersion`. Provide the subscription ID returned by the original subscription call.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `chain_subscribeRuntimeVersion`.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeRuntimeVersion",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the subscription ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "chain_unsubscribeRuntimeVersion",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Upgrade monitor cleanup** -- Stop a runtime-version watcher once your process no longer needs upgrade notifications.
- **Controlled reconnects** -- Replace an existing subscription cleanly before creating a new one.

## Notes

- Use the subscription ID from `chain_subscribeRuntimeVersion`.
- A successful response returns `true`.
- This method is only available over WebSocket.

## Related Methods

- [`chain_subscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_subscribeRuntimeVersion) -- Start the runtime-version subscription
- [`state_subscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_subscribeRuntimeVersion) -- Equivalent subscription via the state namespace

---

## chainHead_v1_body - Bittensor RPC Method

# chainHead_v1_body - Bittensor RPC Method

Retrieves the block body (list of extrinsics) for a block that is part of an active `chainHead_v1_follow` subscription. The block must have been reported by the follow subscription -- you cannot query arbitrary historical blocks. This method is part of the new JSON-RPC v2 chain head specification designed for efficient real-time chain tracking.

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID returned by `chainHead_v1_follow`.
- `hash` (`string, required`): Hex-encoded block hash. Must be a block reported by the follow subscription.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_body",
  "params": [
    "<followSubscription>",
    "<hash>"
  ],
  "id": 1
}
```

## Response Fields

- `result.result` (`"started"` or `"limitReached", required`): `"started"` includes an `operationId`; `"limitReached"` means the node refused to start another operation
- `result.operationId` (`string, required`): Operation ID used to correlate follow-up events when the response is `"started"`

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "result.result": "<value>",
    "result.operationId": "<value>"
  }
}
```

## Use Cases

- **Real-time indexing** -- Fetch block bodies as new blocks arrive to index Bittensor extrinsics in real-time.
- **Transaction monitoring** -- Inspect the extrinsics in each new block to detect specific transactions (transfers, subnet registrations, staking operations).
- **Block explorer backends** -- Serve block body data to users as new blocks are produced.

## Notes

- Requires an active `chainHead_v1_follow` subscription. The block hash must be pinned (reported) by that subscription.
- This method is experimental and may not be enabled on public shared RPC endpoints.
- Use `chainHead_v1_stopOperation` to cancel an in-progress body fetch.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start following the chain head (required before using this method)
- [`chainHead_v1_header`](https://www.dwellir.com/docs/bittensor/chainHead_v1_header) -- Get the header for a followed block
- [`chainHead_v1_call`](https://www.dwellir.com/docs/bittensor/chainHead_v1_call) -- Execute a runtime call on a followed block
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop the follow subscription
- [`archive_v1_body`](https://www.dwellir.com/docs/bittensor/archive_v1_body) -- Get block body for arbitrary historical blocks
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) -- Legacy method to retrieve a full block

---

## chainHead_v1_call - Bittensor RPC Method

# chainHead_v1_call - Bittensor RPC Method

Executes a runtime API function against the state of a block that is pinned by an active `chainHead_v1_follow` subscription. This allows you to call any runtime API (such as `Metadata_metadata`, `AccountNonceApi_account_nonce`, or custom Bittensor runtime APIs) at a specific block known to the follow subscription.

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID from `chainHead_v1_follow`.
- `hash` (`string, required`): Hex-encoded block hash. Must be pinned by the follow subscription.
- `function` (`string, required`): Runtime API function name (e.g. `"Metadata_metadata"`).
- `callParameters` (`string, required`): Hex-encoded SCALE-encoded input parameters. Use `"0x"` for no arguments.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_call",
  "params": [
    "<followSubscription>",
    "<hash>",
    "<function>",
    "<callParameters>"
  ],
  "id": 1
}
```

## Response Fields

- `result.result` (`"started"` or `"limitReached", required`): `"started"` includes an `operationId`; `"limitReached"` means the node refused to start another operation
- `result.operationId` (`string, required`): Operation ID used to correlate follow-up events when the response is `"started"`

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "result.result": "<value>",
    "result.operationId": "<value>"
  }
}
```

## Use Cases

- **Live metadata tracking** -- Fetch runtime metadata at each new block to detect runtime upgrades on Bittensor in real time.
- **Nonce resolution** -- Call `AccountNonceApi_account_nonce` at the latest block to get the correct nonce for transaction submission.
- **Custom runtime queries** -- Invoke Bittensor-specific runtime APIs to query subnet information, neuron data, or stake details at a known block.

## Notes

- Requires an active `chainHead_v1_follow` subscription with the block hash pinned.
- The `callParameters` must be SCALE-encoded. Use a codec library to encode them.
- This method is experimental and may not be enabled on public shared RPC endpoints.
- Use `chainHead_v1_stopOperation` to cancel an in-progress call.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start the follow subscription (required first)
- [`chainHead_v1_storage`](https://www.dwellir.com/docs/bittensor/chainHead_v1_storage) -- Query storage on a followed block
- [`chainHead_v1_header`](https://www.dwellir.com/docs/bittensor/chainHead_v1_header) -- Get header for a followed block
- [`archive_v1_call`](https://www.dwellir.com/docs/bittensor/archive_v1_call) -- Runtime call on historical archive blocks
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Legacy runtime API call method

---

## chainHead_v1_continue - Bittensor RPC Method

# chainHead_v1_continue - Bittensor RPC Method

Resumes a paused operation within an active `chainHead_v1_follow` subscription. Some operations (like storage queries returning large result sets) are delivered in pages. When the node pauses to apply backpressure, it sends an `operationWaitingForContinue` event. You must call this method to receive the next page of results.

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID from `chainHead_v1_follow`.
- `operationId` (`string, required`): The operation ID from the paused operation's `operationWaitingForContinue` event.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_continue",
  "params": [
    "<followSubscription>",
    "<operationId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`null, required`): Acknowledges the continue request. The next page of results will be delivered as a follow subscription notification.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Large storage queries** -- When querying many storage keys via `chainHead_v1_storage`, the node may pause after delivering a batch. Call `continue` to receive the next batch.
- **Backpressure handling** -- Implement proper flow control in your client by processing each batch before requesting the next one with `continue`.
- **Reliable data streaming** -- Ensure no data is lost by acknowledging each page before the node sends the next.

## Notes

- This method is part of the new JSON-RPC v2 specification and works only within a follow subscription context.
- Only call `continue` after receiving an `operationWaitingForContinue` event. Calling it at other times will return an error.
- This method is experimental and may not be available on public shared RPC endpoints.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start the follow subscription
- [`chainHead_v1_storage`](https://www.dwellir.com/docs/bittensor/chainHead_v1_storage) -- Storage queries that may require pagination via continue
- [`chainHead_v1_stopOperation`](https://www.dwellir.com/docs/bittensor/chainHead_v1_stopOperation) -- Cancel an operation instead of continuing it
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop the entire follow subscription

---

## chainHead_v1_follow - Bittensor RPC Method

# chainHead_v1_follow - Bittensor RPC Method

Starts a follow subscription that tracks the chain head in real time over a WebSocket connection. The subscription emits events as new blocks are produced, finalized, or pruned. Blocks reported by the subscription are "pinned" and can be queried with `chainHead_v1_header`, `chainHead_v1_body`, `chainHead_v1_call`, and `chainHead_v1_storage`. This is the entry point for the new JSON-RPC v2 chain head API.

zed`| Emitted once with`finalizedBlockHashes`and, when requested, runtime info. |
|`newBlock`| A new block has been imported. Contains the block hash, parent hash, and optional runtime info. |
|`bestBlockChanged`| The best (most recent non-finalized) block has changed. |
|`finalized`| One or more blocks have been finalized. Contains arrays of finalized and pruned block hashes. |
|`stop\` | The subscription has been terminated by the server (e.g. too many pinned blocks). |

## Code Examples

## Request Parameters

- `withRuntime` (`boolean, required`): If `true`, the subscription includes runtime information (spec version, APIs) in `newBlock` events. Set to `true` if you need to detect runtime upgrades.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_follow",
  "params": [
    "<withRuntime>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Returns a subscription ID and begins streaming events: | Event | Description | |-------|-------------| | `initialized` | Emitted once with `finalizedBlockHashes` and, when requested, runtime info. | | `newBlock` | A new block has been imported. Contains the block hash, parent hash, and optional runtime info. | | `bestBlockChanged` | The best (most recent non-finalized) block has changed. | | `finalized` | One or more blocks have been finalized. Contains arrays of finalized and pruned block hashes. | | `stop` | The subscription has been terminated by the server (e.g. too many pinned blocks). |

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Use Cases

- **Real-time block processing** -- Build indexers or explorers that react to new Bittensor blocks as they arrive, without polling.
- **Finality tracking** -- Know exactly when blocks are finalized by GRANDPA, enabling safe database commits and user confirmations.
- **Runtime upgrade detection** -- With `withRuntime: true`, detect spec version changes immediately to update your type registry and decoders.
- **Fork awareness** -- The `finalized` event reports pruned blocks, allowing your application to handle chain reorganizations correctly.

## Notes

- This method is the foundation of the new JSON-RPC v2 chain head API. All other `chainHead_v1_*` methods require an active follow subscription.
- The server limits the number of pinned (non-finalized) blocks. If the limit is reached, the subscription is stopped with a `stop` event. Unpin blocks by calling `chainHead_v1_unpin` when you are done with them.
- This method is experimental and may not be enabled on public shared RPC endpoints.
- Use `chainHead_v1_unfollow` to cleanly stop the subscription.

## Related Methods

- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop the follow subscription
- [`chainHead_v1_header`](https://www.dwellir.com/docs/bittensor/chainHead_v1_header) -- Get a header for a pinned block
- [`chainHead_v1_body`](https://www.dwellir.com/docs/bittensor/chainHead_v1_body) -- Get the body of a pinned block
- [`chainHead_v1_call`](https://www.dwellir.com/docs/bittensor/chainHead_v1_call) -- Execute a runtime call at a pinned block
- [`chainHead_v1_storage`](https://www.dwellir.com/docs/bittensor/chainHead_v1_storage) -- Query storage at a pinned block
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Legacy subscription for new block headers

---

## chainHead_v1_header - Bittensor RPC Method

# chainHead_v1_header - Bittensor RPC Method

Returns the SCALE-encoded header of a block that is pinned by an active `chainHead_v1_follow` subscription. Unlike `chainHead_v1_body` and `chainHead_v1_call`, this method returns the result directly (not as a streamed operation), making it the fastest way to inspect block metadata within the follow API.

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID from `chainHead_v1_follow`.
- `hash` (`string, required`): Hex-encoded block hash. Must be pinned by the follow subscription.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_header",
  "params": [
    "<followSubscription>",
    "<hash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded SCALE-encoded block header for the requested pinned block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Block number tracking** -- Decode the header to get the block number for display or indexing as each new block arrives.
- **State root verification** -- Verify the state root for light-client proofs or cross-chain bridges.
- **Parent chain traversal** -- Follow `parentHash` links to walk back through recent blocks within the follow window.

## Notes

- This is a synchronous response (not an operation-based flow), so results are returned immediately.
- The block hash must be pinned by the follow subscription. Querying an unpinned or unknown hash returns an error.
- This method is experimental and may not be enabled on public shared RPC endpoints.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start the follow subscription (required first)
- [`chainHead_v1_body`](https://www.dwellir.com/docs/bittensor/chainHead_v1_body) -- Get the block body for a pinned block
- [`chainHead_v1_call`](https://www.dwellir.com/docs/bittensor/chainHead_v1_call) -- Execute a runtime call at a pinned block
- [`archive_v1_header`](https://www.dwellir.com/docs/bittensor/archive_v1_header) -- Get headers for arbitrary historical blocks
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) -- Legacy method to get a block header

---

## chainHead_v1_stopOperation - Bittensor RPC Method

# chainHead_v1_stopOperation - Bittensor RPC Method

Cancels an in-progress operation (body fetch, runtime call, or storage query) within an active `chainHead_v1_follow` subscription. Operations started by `chainHead_v1_body`, `chainHead_v1_call`, or `chainHead_v1_storage` return an `operationId`; pass that ID to this method to cancel the operation and free server resources.

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID from `chainHead_v1_follow`.
- `operationId` (`string, required`): The operation ID returned when the operation was started.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_stopOperation",
  "params": [
    "<followSubscription>",
    "<operationId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`null, required`): Confirms the operation has been stopped.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Timeout handling** -- Cancel an operation that is taking too long to complete, such as a large storage query.
- **Resource management** -- Stop unnecessary operations to stay within the server's concurrent operation limits.
- **Graceful error recovery** -- Cancel a stalled operation and retry with different parameters or at a different block.

## Notes

- This method is part of the new JSON-RPC v2 chain head specification.
- Only operations that have been started (returned `"started"` with an `operationId`) can be stopped.
- `chainHead_v1_header` returns results synchronously and does not use the operation pattern, so it cannot be stopped with this method.
- This method is experimental and may not be enabled on public shared RPC endpoints.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start the follow subscription
- [`chainHead_v1_continue`](https://www.dwellir.com/docs/bittensor/chainHead_v1_continue) -- Resume a paused operation instead of stopping it
- [`chainHead_v1_unfollow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_unfollow) -- Stop the entire follow subscription (also stops all operations)
- [`archive_v1_stopStorage`](https://www.dwellir.com/docs/bittensor/archive_v1_stopStorage) -- Stop an archive storage operation

---

## chainHead_v1_storage - Bittensor RPC Method

# chainHead_v1_storage - Bittensor RPC Method

Queries on-chain storage at a block that is pinned by an active `chainHead_v1_follow` subscription. You can request values, hashes, closest descendant Merkle values, or enumerate descendants for one or more storage keys. Results are streamed via the follow subscription and may be paginated (requiring `chainHead_v1_continue` calls).

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID from `chainHead_v1_follow`.
- `hash` (`string, required`): Hex-encoded block hash. Must be pinned by the follow subscription.
- `items` (`array, required`): Array of storage query items.
- `childTrie` (`string, optional`): Hex-encoded child trie key if querying child storage. Omit for main state trie.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_storage",
  "params": [
    "<followSubscription>",
    "<hash>",
    "<items>",
    "<childTrie>"
  ],
  "id": 1
}
```

## Response Fields

- `result.result` (`"started"` or `"limitReached", required`): `"started"` includes an `operationId`; `"limitReached"` means the node refused to start another operation
- `result.operationId` (`string, required`): Operation ID used to correlate follow-up events when the response is `"started"`
- `result.discardedItems` (`number, required`): Number of requested items the node discarded before starting, when applicable

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "result.result": "<value>",
    "result.operationId": "<value>",
    "result.discardedItems": "0x1"
  }
}
```

## Use Cases

- **Live state reads** -- Query account balances, staking state, or Bittensor subnet parameters at the latest finalized block.
- **Bulk key enumeration** -- Use `descendantsValues` to retrieve all entries under a storage prefix for a given block.
- **Merkle proof generation** -- Use `closestDescendantMerkleValue` for light-client or bridge verification.

## Notes

- Large result sets are paginated with `operationWaitingForContinue` events. Call `chainHead_v1_continue` to get more.
- Use `chainHead_v1_stopOperation` to cancel a slow or unnecessary storage query.
- This method is experimental and may not be enabled on public shared RPC endpoints.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start the follow subscription (required first)
- [`chainHead_v1_continue`](https://www.dwellir.com/docs/bittensor/chainHead_v1_continue) -- Resume paginated storage results
- [`chainHead_v1_call`](https://www.dwellir.com/docs/bittensor/chainHead_v1_call) -- Runtime call at a followed block
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Legacy storage read
- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Legacy paginated key enumeration

---

## chainHead_v1_unfollow - Bittensor RPC Method

# chainHead_v1_unfollow - Bittensor RPC Method

Stops a chain head follow subscription that was started with `chainHead_v1_follow`. This cancels all in-progress operations, unpins all blocks, and frees all server-side resources associated with the subscription. Always call this method when you are done following the chain head to avoid resource leaks.

## Code Examples

## Request Parameters

- `followSubscription` (`string, required`): The subscription ID returned by `chainHead_v1_follow`.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainHead_v1_unfollow",
  "params": [
    "<followSubscription>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`boolean, required`): Indicates whether the follow subscription was successfully stopped. No further events will be delivered.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Graceful shutdown** -- Clean up the follow subscription before disconnecting your WebSocket client.
- **Subscription rotation** -- Stop the current subscription and start a new one (e.g. after a `stop` event indicating too many pinned blocks).
- **Resource management** -- Free server resources when your application no longer needs real-time block notifications.

## Notes

- After calling `unfollow`, the subscription ID becomes invalid and all associated operations are cancelled.
- If the server already sent a `stop` event, the subscription is already terminated, but calling `unfollow` is still safe and recommended for clean client-side state management.
- This method is experimental and may not be enabled on public shared RPC endpoints.

## Related Methods

- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Start a new follow subscription
- [`chainHead_v1_stopOperation`](https://www.dwellir.com/docs/bittensor/chainHead_v1_stopOperation) -- Stop a single operation without ending the subscription
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Legacy unsubscribe from new block headers
- [`chain_unsubscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeFinalizedHeads) -- Legacy unsubscribe from finalized headers

---

## chainSpec_v1_chainName - JSON-RPC Method

# chainSpec_v1_chainName - JSON-RPC Method

## Description

Read static chain specification data such as chain name, ss58 properties, and genesis hash. Use this to configure clients (address format, token info) or verify you are talking to the expected network.

Returns the chain name from the runtime's ChainSpec.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainSpec_v1_chainName",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Human-readable chain name returned by the connected node.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Bittensor"
}
```

---

## chainSpec_v1_genesisHash - Bittensor RPC Method

# chainSpec_v1_genesisHash - Bittensor RPC Method

Returns the genesis block hash as defined in the chain specification. The genesis hash is a unique identifier for a Substrate-based chain and is used during transaction signing, network verification, and multi-chain client configuration. On Bittensor mainnet this value is fixed and never changes.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainSpec_v1_genesisHash",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded 32-byte blake2b hash of the genesis block (e.g. `"0x2f07..."`)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Network verification** -- Confirm that the RPC endpoint is serving Bittensor mainnet by comparing the genesis hash against the known value. This prevents accidental transactions on the wrong network.
- **Transaction signing** -- The genesis hash is a required component of the signed extrinsic payload. An incorrect value causes `BadProof` errors.
- **Multi-chain routing** -- In applications that connect to multiple Substrate chains, use the genesis hash to identify which chain a connection belongs to.
- **Client initialization** -- Configure client libraries (like `@polkadot/api`) with the genesis hash to enable proper address encoding and transaction construction.

## Notes

- This method is part of the new JSON-RPC v2 `chainSpec` namespace alongside `chainSpec_v1_chainName` and `chainSpec_v1_properties`.
- The genesis hash is immutable and can be safely cached indefinitely.
- This method is available on most node configurations including public RPC endpoints.

## Related Methods

- [`chainSpec_v1_properties`](https://www.dwellir.com/docs/bittensor/chainSpec_v1_properties) -- Get chain properties (SS58 prefix, token symbol, decimals)
- [`archive_v1_genesisHash`](https://www.dwellir.com/docs/bittensor/archive_v1_genesisHash) -- Get genesis hash via the archive namespace
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) -- Legacy method; pass `0` to get the genesis hash
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Legacy method for chain properties

---

## chainSpec_v1_properties - Bittensor RPC Method

# chainSpec_v1_properties - Bittensor RPC Method

Returns the chain properties as defined in the chain specification. These properties describe the network's address format, native token, and other static configuration. For Bittensor mainnet, this returns the SS58 prefix (42), the native token symbol (TAO), and the token decimals (9).

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chainSpec_v1_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`object, required`): A JSON object with chain-defined properties.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Use Cases

- **Address formatting** -- Use the `ss58Format` value to correctly encode and decode Bittensor SS58 addresses in your application.
- **Balance display** -- Use `tokenDecimals` and `tokenSymbol` to convert raw balance values (in rao) to human-readable TAO amounts.
- **Client configuration** -- Initialize wallet libraries and UIs with the correct token metadata without hardcoding values.
- **Multi-chain support** -- Dynamically configure your application for different Substrate chains by reading properties at startup.

## Notes

- This method is part of the new JSON-RPC v2 `chainSpec` namespace.
- The returned properties are static and never change for a given chain, so they can be cached.
- This is the v2 equivalent of the legacy `system_properties` method.

## Related Methods

- [`chainSpec_v1_genesisHash`](https://www.dwellir.com/docs/bittensor/chainSpec_v1_genesisHash) -- Get the genesis hash from the chain spec
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Legacy method returning the same information
- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the human-readable chain name

---

## childstate_getKeys - JSON-RPC Method

# childstate_getKeys - JSON-RPC Method

## Description

Read from child tries (nested storage) including listing keys and fetching values. Useful for pallets that isolate state in child trees.

Returns child storage keys for a given child storage root and key prefix.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `prefix` (`string, required`): Hex-encoded key prefix to match inside the child trie. Use `0x` to enumerate the whole trie.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getKeys",
  "params": [
    "<childStorageKey>",
    "0x"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array<string>, required`): Hex-encoded child trie keys matching the prefix at the best block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Notes

- Replace `0xCHILD_STORAGE_KEY` with the actual child trie root for the pallet or contract you are querying.
- Public Bittensor endpoints do not expose a stable example child trie, so you need a chain-specific child storage key before this call will return data.

---

## childstate_getKeysPaged - JSON-RPC Method

# childstate_getKeysPaged - JSON-RPC Method

## Description

Read from child tries (nested storage) including listing keys and fetching values. Useful for pallets that isolate state in child trees.

Returns child storage keys for a given child root and key prefix, paginated.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `prefix` (`string, required`): Hex-encoded prefix to filter child storage keys. Use `0x` for all keys.
- `count` (`number, required`): Maximum number of keys to return in this page.
- `startKey` (`string, optional`): Optional cursor key from the previous page.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getKeysPaged",
  "params": [
    "<childStorageKey>",
    "0x",
    100,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array<string>, required`): Page of matching child trie keys. Returns fewer than `count` items at the end of the scan.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Notes

- Replace `0xCHILD_STORAGE_KEY` with the child trie root you want to inspect.
- Use `"0x"` as the prefix to enumerate the whole trie, then page forward with the returned cursor.

---

## childstate_getKeysPagedAt - Bittensor RPC Method

# childstate_getKeysPagedAt - Bittensor RPC Method

Returns child storage keys matching a prefix with cursor-based pagination at a specific block hash. Child tries are separate state trees used by certain Substrate pallets to isolate their storage from the main state trie. This method is the child-trie equivalent of `state_getKeysPaged` but with explicit block hash targeting.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `prefix` (`string, required`): Hex-encoded prefix to filter child storage keys. Use `"0x"` for all keys.
- `count` (`number, required`): Maximum number of keys to return per page.
- `startKey` (`string, optional`): Hex-encoded key to start after (cursor for pagination). Omit for the first page.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getKeysPagedAt",
  "params": [
    "<childStorageKey>",
    "<prefix>",
    "<count>",
    "<startKey>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded child storage keys matching the prefix. Empty array when no more keys exist.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Child trie enumeration** -- List all keys stored in a child trie, such as contract storage or pallet-specific isolated state.
- **Historical queries** -- Enumerate child storage keys as they existed at a specific block for auditing or analysis.
- **Paginated iteration** -- Iterate over large child tries without loading all keys into memory at once.

## Notes

- Child tries are used by pallets that need isolated storage (e.g. smart contracts). Not all pallets use child storage.
- If the child storage key is invalid or the child trie does not exist, the result will be an empty array.
- Requires an archive node for queries at historical block hashes.

## Related Methods

- [`childstate_getKeysPaged`](https://www.dwellir.com/docs/bittensor/childstate_getKeysPaged) -- Same functionality at the best block
- [`childstate_getStorage`](https://www.dwellir.com/docs/bittensor/childstate_getStorage) -- Read a value from child storage
- [`childstate_getStorageEntries`](https://www.dwellir.com/docs/bittensor/childstate_getStorageEntries) -- Read multiple child storage values at once
- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Paginated key enumeration for the main state trie

---

## childstate_getStorage - JSON-RPC Method

# childstate_getStorage - JSON-RPC Method

## Description

Read from child tries (nested storage) including listing keys and fetching values. Useful for pallets that isolate state in child trees.

Returns the SCALE-encoded value for a child storage key.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `key` (`string, required`): Hex-encoded storage key to read from the child trie.
- `blockHash` (`string, optional`): Optional block hash for historical reads. Defaults to the best block.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getStorage",
  "params": [
    "<childStorageKey>",
    "<key>",
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string | null, required`): Hex-encoded SCALE value stored at the child trie key, or `null` when no value exists.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x01020304"
}
```

## Notes

- Replace `0xCHILD_STORAGE_KEY` with the actual child trie root and `0xSTORAGE_KEY` with a concrete key inside that trie.
- Child-storage lookups are runtime-specific. Without a valid child trie root, the node will reject the request or return no data.

---

## childstate_getStorageEntries - Bittensor RPC Method

# childstate_getStorageEntries - Bittensor RPC Method

Returns the values for multiple child storage keys in a single request. This is the batch equivalent of `childstate_getStorage` and is useful when you need to read several entries from a child trie efficiently without making individual RPC calls for each key.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `keys` (`array, required`): Array of hex-encoded storage keys to read from the child trie.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getStorageEntries",
  "params": [
    "<childStorageKey>",
    "<keys>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded SCALE-encoded values, in the same order as the input keys. `null` for keys that do not exist.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Batch child state reads** -- Efficiently read multiple values from a child trie (e.g. contract storage slots) in one round-trip.
- **Snapshot tooling** -- Export multiple child storage entries at a specific block for state snapshots or migrations.
- **Data aggregation** -- Collect multiple related values from a pallet's child storage for dashboards or analytics.

## Notes

- Child tries are used by pallets that isolate their storage (e.g. smart contracts on the EVM layer). Most standard Substrate storage lives in the main trie.
- Values are SCALE-encoded and must be decoded according to the pallet's storage type definitions.
- If the child trie does not exist, all entries will be `null`.

## Related Methods

- [`childstate_getStorage`](https://www.dwellir.com/docs/bittensor/childstate_getStorage) -- Read a single value from child storage
- [`childstate_getKeysPagedAt`](https://www.dwellir.com/docs/bittensor/childstate_getKeysPagedAt) -- Enumerate child storage keys with pagination
- [`childstate_getStorageSize`](https://www.dwellir.com/docs/bittensor/childstate_getStorageSize) -- Get the byte size of a child storage value
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read from the main state trie

---

## childstate_getStorageHash - JSON-RPC Method

# childstate_getStorageHash - JSON-RPC Method

## Description

Read from child tries (nested storage) including listing keys and fetching values. Useful for pallets that isolate state in child trees.

Returns the storage hash for a child storage key.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `key` (`string, required`): Hex-encoded storage key to hash.
- `blockHash` (`string, optional`): Optional block hash for historical reads. Defaults to the best block.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getStorageHash",
  "params": [
    "<childStorageKey>",
    "<key>",
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string | null, required`): Hex-encoded storage hash for the child trie key, or `null` when the key is absent.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x84aea08073c027fa3c5ecf0079b6beec969f8afc5558329b18616949ceb257af"
}
```

## Notes

- Replace `0xCHILD_STORAGE_KEY` with the child trie root and `0xSTORAGE_KEY` with the entry you want to fingerprint.
- Use this when you need a compact integrity check for child storage without fetching the full SCALE payload.

---

## childstate_getStorageSize - Bittensor RPC Method

# childstate_getStorageSize - Bittensor RPC Method

Returns the size in bytes of a value stored in a child trie. This is useful for checking whether a child storage entry exists and determining its size before fetching the full value, which can be helpful for resource planning and bandwidth management.

ze in bytes of the storage value, or `null` if the key does not exist in the child trie. |

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `key` (`string, required`): Hex-encoded storage key within the child trie.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "childstate_getStorageSize",
  "params": [
    "<childStorageKey>",
    "<key>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`number` or `null, required`): Size in bytes of the storage value, or `null` if the key does not exist in the child trie.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Use Cases

- **Existence check** -- Determine whether a child storage key exists without fetching its value (returns `null` if absent).
- **Size estimation** -- Estimate bandwidth and memory requirements before reading large child storage values.
- **Storage monitoring** -- Track the size of contract storage or other child trie entries over time.

## Notes

- Child tries are used by pallets that isolate their storage. Most common Substrate storage lives in the main trie.
- The size returned is for the raw SCALE-encoded value, not the decoded value.
- Returns `null` for non-existent keys rather than 0.

## Related Methods

- [`childstate_getStorage`](https://www.dwellir.com/docs/bittensor/childstate_getStorage) -- Read the actual value for a child storage key
- [`childstate_getStorageEntries`](https://www.dwellir.com/docs/bittensor/childstate_getStorageEntries) -- Batch-read multiple child storage values
- [`childstate_getStorageHash`](https://www.dwellir.com/docs/bittensor/childstate_getStorageHash) -- Get the hash of a child storage value
- [`state_getStorageSize`](https://www.dwellir.com/docs/bittensor/state_getStorageSize) -- Get the size of a main-trie storage value

---

## debug_getBadBlocks - Bittensor RPC Method

# debug_getBadBlocks - Bittensor RPC Method

Returns a list of "bad" blocks that the node has encountered during import or execution. Bad blocks are blocks that failed validation, execution, or consensus checks. This method is part of the EVM-compatible `debug` namespace provided by the Frontier EVM layer on Bittensor and mirrors the Ethereum `debug_getBadBlocks` method.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getBadBlocks",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of bad block objects, or an empty array if no bad blocks have been recorded.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Node diagnostics** -- Identify blocks that failed import or execution to diagnose consensus issues or runtime bugs.
- **Network health monitoring** -- Detect whether bad blocks are being produced on the Bittensor EVM layer.
- **Forensic analysis** -- Examine the contents of bad blocks to understand why they were rejected.

## Notes

- This method is often disabled on public RPC endpoints. It may require the node to be started with debug flags or `--rpc-methods unsafe`.
- On a healthy network, the result is typically an empty array.
- This is an EVM debug method provided by the Frontier compatibility layer. It operates on the EVM view of blocks, not the Substrate view.

## Related Methods

- [`debug_getRawBlock`](https://www.dwellir.com/docs/bittensor/debug_getRawBlock) -- Get raw block data by number
- [`debug_getRawHeader`](https://www.dwellir.com/docs/bittensor/debug_getRawHeader) -- Get raw header data by number
- [`debug_getRawTransaction`](https://www.dwellir.com/docs/bittensor/debug_getRawTransaction) -- Get raw transaction data by hash
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) -- Get an EVM block by number

---

## debug_getRawBlock - Bittensor RPC Method

# debug_getRawBlock - Bittensor RPC Method

Returns the raw RLP-encoded block data for a given block number on Bittensor's EVM-compatible layer. This is a low-level debug method that provides the raw serialized block as it would appear on the wire in Ethereum's RLP encoding. It is part of the `debug` namespace provided by the Frontier EVM compatibility layer.

## Code Examples

## Request Parameters

- `blockNumber` (`string, required`): Block number as a hex string (e.g. `"0xF4240"` for block 1000000), or `"latest"`, `"earliest"`, `"pending"`.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawBlock",
  "params": [
    "<blockNumber>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded RLP-encoded block data.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Raw block analysis** -- Inspect the exact RLP-encoded representation of a block for debugging encoding/decoding issues.
- **Tooling development** -- Build or test RLP decoders and block parsers against real Bittensor EVM block data.
- **Data archival** -- Store raw block data in its canonical serialized form.

## Notes

- This is an EVM debug method provided by the Frontier compatibility layer. It may be disabled on public RPC endpoints.
- The raw data is RLP-encoded (Ethereum's serialization format), not SCALE-encoded (Substrate's format).
- For Substrate-native block data, use `chain_getBlock` instead.
- May require `--rpc-methods unsafe` or Frontier debug flags enabled.

## Related Methods

- [`debug_getRawHeader`](https://www.dwellir.com/docs/bittensor/debug_getRawHeader) -- Get raw RLP-encoded header data
- [`debug_getRawTransaction`](https://www.dwellir.com/docs/bittensor/debug_getRawTransaction) -- Get raw RLP-encoded transaction data
- [`debug_getBadBlocks`](https://www.dwellir.com/docs/bittensor/debug_getBadBlocks) -- List bad blocks the node has encountered
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) -- Get a decoded EVM block by number
- [`chain_getBlock`](https://www.dwellir.com/docs/bittensor/chain_getBlock) -- Get a Substrate-native block

---

## debug_getRawHeader - Bittensor RPC Method

# debug_getRawHeader - Bittensor RPC Method

Returns the raw RLP-encoded block header for a given block number on Bittensor's EVM-compatible layer. This is a lightweight debug method that provides just the header portion of the block in Ethereum's RLP encoding, without the transaction body. It is part of the `debug` namespace provided by the Frontier EVM compatibility layer.

## Code Examples

## Request Parameters

- `blockNumber` (`string, required`): Block number as a hex string (e.g. `"0xF4240"`), or `"latest"`, `"earliest"`, `"pending"`.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawHeader",
  "params": [
    "<blockNumber>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded RLP-encoded block header data.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Header verification** -- Inspect the raw RLP-encoded header to verify encoding correctness or debug header-related issues.
- **Light client development** -- Obtain raw headers for building or testing EVM-compatible light client implementations.
- **Tooling development** -- Test RLP header decoders against real Bittensor EVM header data.

## Notes

- This is an EVM debug method provided by the Frontier compatibility layer. It may be disabled on public RPC endpoints.
- The raw data uses RLP encoding (Ethereum format), not SCALE encoding (Substrate format).
- For the decoded header, use `eth_getBlockByNumber` with the second parameter set to `false`.
- May require `--rpc-methods unsafe` or Frontier debug flags enabled.

## Related Methods

- [`debug_getRawBlock`](https://www.dwellir.com/docs/bittensor/debug_getRawBlock) -- Get raw RLP-encoded full block data
- [`debug_getRawTransaction`](https://www.dwellir.com/docs/bittensor/debug_getRawTransaction) -- Get raw RLP-encoded transaction data
- [`debug_getBadBlocks`](https://www.dwellir.com/docs/bittensor/debug_getBadBlocks) -- List bad blocks
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) -- Get a decoded EVM block
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) -- Get a Substrate-native block header

---

## debug_getRawReceipts - JSON-RPC Method

# debug_getRawReceipts - JSON-RPC Method

## Description

Fetch raw SCALE‑encoded headers, blocks, or receipts for deep debugging or tooling. Usually disabled on public RPC.

Returns raw receipts for a block. Applies to Frontier EVM context.

## Code Examples

## Request Parameters

- `blockHash` (`string, required`): Hex-encoded block hash whose Frontier receipts you want to inspect.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawReceipts",
  "params": [
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array<string> | null, required`): Array of raw RLP-encoded receipt bytes for the block, or `null` when receipts are unavailable.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

---

## debug_getRawTransaction - Bittensor RPC Method

# debug_getRawTransaction - Bittensor RPC Method

Returns the raw RLP-encoded transaction data for a given transaction hash on Bittensor's EVM-compatible layer. This provides the exact bytes of the signed transaction as it was submitted to the network, before any decoding. It is part of the `debug` namespace provided by the Frontier EVM compatibility layer.

## Code Examples

## Request Parameters

- `txHash` (`string, required`): The EVM transaction hash (32-byte hex string with `0x` prefix).

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawTransaction",
  "params": [
    "<txHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string` or `null, required`): Hex-encoded RLP-encoded transaction data, or `null` if the transaction is not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Transaction debugging** -- Inspect the raw signed transaction bytes to debug encoding, signing, or submission issues on Bittensor's EVM layer.
- **Transaction replay** -- Obtain the raw transaction to replay it on a test network or local development environment.
- **Signature verification** -- Extract the raw transaction for independent signature verification.
- **Tooling development** -- Test RLP transaction decoders against real Bittensor EVM transaction data.

## Notes

- This is an EVM debug method provided by the Frontier compatibility layer. It may be disabled on public RPC endpoints.
- The raw data uses RLP encoding (Ethereum format). The transaction includes nonce, gas price, gas limit, to, value, data, and signature fields.
- Returns `null` if the transaction hash is not found or has been pruned.
- May require `--rpc-methods unsafe` or Frontier debug flags enabled.

## Related Methods

- [`debug_getRawBlock`](https://www.dwellir.com/docs/bittensor/debug_getRawBlock) -- Get raw RLP-encoded block data
- [`debug_getRawHeader`](https://www.dwellir.com/docs/bittensor/debug_getRawHeader) -- Get raw RLP-encoded header data
- [`debug_getBadBlocks`](https://www.dwellir.com/docs/bittensor/debug_getBadBlocks) -- List bad blocks
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bittensor/eth_getTransactionByHash) -- Get a decoded EVM transaction
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bittensor/eth_getTransactionReceipt) -- Get the transaction receipt

---

## delegateInfo_getDelegate - Bittensor RPC Method

# delegateInfo_getDelegate - Bittensor RPC Method

## Overview

The `delegateInfo_getDelegate` method returns SCALE-encoded information for a specific delegate identified by their hotkey bytes. This is the targeted version of `delegateInfo_getDelegates` -- use it when you already know which delegate you want to inspect.

Delegates are validator hotkeys that accept nominated TAO stake from other accounts. Each delegate has a configurable take rate, a list of nominators, and registrations across one or more subnets. This method is commonly used in staking UIs to show detailed delegate profiles before a user commits to delegation.

zed `u16` value |
\| `nominators` | `Vec<(AccountId32, Vec<(NetUid, stake)>)>` | Nominator entries grouped by subnet and stake amount |
\| `owner_ss58` | `AccountId32` | The coldkey that owns this delegate hotkey |
\| `registrations` | `Vec<Compact<u16>>` | Subnet netuids where this delegate is registered |
\| `validator_permits` | `Vec<Compact<u16>>` | Subnet netuids where this delegate has validator permits |
\| `return_per_1000` | `Compact<u64>` | Estimated delegator return per 1000 TAO staked |
\| `total_daily_return` | `Compact<u64>` | Estimated total daily delegator return |

Returns `null` if the provided account is not a registered delegate.

## SCALE Decoding

The raw response requires SCALE decoding with Bittensor type definitions.

**Using `@polkadot/api`:** Register Bittensor custom types (including the `DelegateInfo` struct) before creating the API instance. The response decodes to a single `DelegateInfo` struct (or `Option<DelegateInfo>` that can be empty).

**Using `scalecodec` (Python):** The `bittensor` SDK handles decoding internally via `sub.get_delegate_by_hotkey()`. For manual decoding, parse the byte-array result as an `Option<DelegateInfo>` using the Bittensor type registry.

**Key decoding notes:**

- The `take` field is normalized over the full `u16` range rather than simple basis points
- All RAO amounts should be divided by `1e9` for TAO display values
- `nominators` is a nested structure that records delegations per subnet, which is why the payload can grow large for active delegates
- An empty/null result means the hotkey is not a registered delegate

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `delegate_account_id` (`number[], required`): Raw 32-byte hotkey public key as a JSON byte array
- `at` (`BlockHash, optional`): Optional block hash to query at a specific block. Pass `null` for the latest state

## Request Example

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const delegateHotkey = '0x0000000000000000000000000000000000000000000000000000000000000000';
const result = await api.rpc.delegateInfo.getDelegate(delegateHotkey);

if (result.isEmpty) {
  console.log('Delegate not found');
} else {
  console.log('Raw SCALE result:', result.toHex().slice(0, 80), '...');
}

await api.disconnect();
```

## Response Fields

- `delegate_ss58` (`AccountId32, required`): The delegate hotkey
- `take` (`Compact<u16>, required`): Delegate take stored as a normalized `u16` value
- `nominators` (`Vec<(AccountId32, Vec<(NetUid, stake)>)>, required`): Nominator entries grouped by subnet and stake amount
- `owner_ss58` (`AccountId32, required`): The coldkey that owns this delegate hotkey
- `registrations` (`Vec<Compact<u16>>, required`): Subnet netuids where this delegate is registered
- `validator_permits` (`Vec<Compact<u16>>, required`): Subnet netuids where this delegate has validator permits
- `return_per_1000` (`Compact<u64>, required`): Estimated delegator return per 1000 TAO staked
- `total_daily_return` (`Compact<u64>, required`): Estimated total daily delegator return

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "delegate_ss58": "<value>",
    "take": "<value>",
    "nominators": "<value>",
    "owner_ss58": "<value>",
    "registrations": "<value>",
    "validator_permits": "<value>",
    "return_per_1000": "<value>",
    "total_daily_return": "<value>"
  }
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

### Error 5

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Replace with a real delegate hotkey as 32 raw bytes
delegate_pubkey = [0] * 32

payload = {
    'jsonrpc': '2.0',
    'method': 'delegateInfo_getDelegate',
    'params': [delegate_pubkey, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    print(f"SCALE byte count: {len(result['result'])}")
else:
    print('Delegate not found or not registered')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# delegate = sub.get_delegate_by_hotkey(delegate_ss58)
# print(f"Take: {delegate.take}, Nominators: {len(delegate.nominators)}")
```

### Full Python example with delegate analysis

```python
import bittensor as bt

sub = bt.subtensor(network='finney')

# Look up a specific delegate by SS58 hotkey address
delegate_ss58 = '5F4tQyWrhfGVcNhoqeiNsR6KjBCapnXJYpGyexNFpbqR2Yq7'
delegate = sub.get_delegate_by_hotkey(delegate_ss58)

if delegate is None:
    print(f"Hotkey {delegate_ss58} is not a registered delegate")
else:
    # Delegate profile
    print(f"Delegate: {delegate.hotkey_ss58}")
    print(f"Owner:    {delegate.owner_ss58}")
    print(f"Take:     {delegate.take * 100:.1f}%")
    print(f"Nominators: {len(delegate.nominators)}")
    print(f"Total stake: {delegate.total_stake.tao:,.2f} TAO")

    # Subnet presence
    print(f"Registered on subnets: {delegate.registrations}")
    print(f"Validator permits on:  {delegate.validator_permits}")

    # Yield estimation
    return_per_1000 = delegate.return_per_1000.tao
    print(f"Return per 1000 TAO: {return_per_1000:.4f} TAO")

    # Top nominators
    sorted_noms = sorted(
        delegate.nominators,
        key=lambda item: sum(amount.tao for _, amount in item[1]),
        reverse=True
    )
    print("\nTop 5 nominators:")
    for addr, stakes in sorted_noms[:5]:
        total = sum(amount.tao for _, amount in stakes)
        print(f"  {addr}: {total:,.2f} TAO across {len(stakes)} subnet entries")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const delegateHotkey = '0x0000000000000000000000000000000000000000000000000000000000000000';
const result = await api.rpc.delegateInfo.getDelegate(delegateHotkey);

if (result.isEmpty) {
  console.log('Delegate not found');
} else {
  console.log('Raw SCALE result:', result.toHex().slice(0, 80), '...');
}

await api.disconnect();
```

### Historical query at a specific block

```python
import requests

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
delegate_pubkey = [0] * 32  # delegate hotkey as raw bytes

# Query at a specific block hash for historical delegate state
block_hash = '0xabc123...'  # a past block hash
payload = {
    'jsonrpc': '2.0',
    'method': 'delegateInfo_getDelegate',
    'params': [delegate_pubkey, block_hash],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()
# Compare with current state to track changes over time
```

## Common Use Cases

- **Validator research** — Inspect a specific delegate's take rate, nominator count, and subnet registrations before delegating TAO.
- **Delegation decisions** — Compare the return per 1000 TAO across candidates to pick the best delegate.
- **Portfolio tracking** — Monitor a delegate's performance over time by querying at specific block hashes.
- **Staking UIs** — Display a delegate's profile page with all relevant staking metrics.
- **Alerting** — Watch for changes in a delegate's take rate or registration status by polling periodically.
- **Nominator analysis** — Inspect the full list of nominators to understand stake concentration and whale exposure.

## Related Methods

- [`delegateInfo_getDelegates`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegates) — Get info for all registered delegates
- [`delegateInfo_getDelegated`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegated) — Get delegations made by a specific account
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the metagraph for a subnet
- [`neuronInfo_getNeuron`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuron) — Get detailed neuron info by UID
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic subnet info including emission data

---

## delegateInfo_getDelegated - Bittensor RPC Method

# delegateInfo_getDelegated - Bittensor RPC Method

## Overview

The `delegateInfo_getDelegated` method returns SCALE-encoded information about all delegations made by a specific account (coldkey). While `delegateInfo_getDelegates` lists delegate profiles, this method answers the question: "Where has this account delegated its TAO?"

This is the primary method for building portfolio views and staking dashboards that show a user's active delegations, the delegates they have nominated, and how much TAO they have staked with each.

zed `u16` value |
\| `nominators` | `Vec<(AccountId32, Vec<(NetUid, stake)>)>` | Full nominator list for the delegate, grouped by subnet |
\| `owner_ss58` | `AccountId32` | The coldkey that owns the delegate hotkey |
\| `registrations` | `Vec<Compact<u16>>` | Subnet netuids where the delegate is registered |
\| `validator_permits` | `Vec<Compact<u16>>` | Subnet netuids where the delegate has validator permits |
\| `return_per_1000` | `Compact<u64>` | Estimated delegator return per 1000 TAO staked |
\| `total_daily_return` | `Compact<u64>` | Estimated total daily delegator return |
\| `netuid` / `alpha_stake` | `(u16, Compact<u64>)` | The subnet identifier and this delegator's stake on that subnet |

Returns an empty list if the account has no active delegations.

## SCALE Decoding

The raw response requires SCALE decoding with Bittensor-specific type definitions.

**Using `@polkadot/api`:** Register the `DelegateInfo` type definition before creating the API instance. The result decodes to `Vec<(DelegateInfo, (u16, Compact<u64>))>`.

**Using `scalecodec` (Python):** The `bittensor` SDK provides `sub.get_delegated()` helpers. For manual decoding, parse the response as a vector pairing `DelegateInfo` with subnet-specific stake data.

**Key decoding notes:**

- Each entry pairs a full `DelegateInfo` struct with the queried account's specific stake amount
- The `nominators` list within each `DelegateInfo` includes all nominators, not just the queried account -- use this to see your share relative to other nominators
- To find your specific stake amount for each delegation, look up the queried `AccountId32` within the `nominators` vector, or use the second tuple element
- Amounts are in RAO (divide by `1e9` for TAO)

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `delegator_account_id` (`number[], required`): Raw 32-byte coldkey public key as a JSON byte array
- `at` (`BlockHash, optional`): Optional block hash to query at a specific block. Pass `null` for the latest state

## Request Example

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const coldkey = '0x0000000000000000000000000000000000000000000000000000000000000000';
const result = await api.rpc.delegateInfo.getDelegated(coldkey);

if (result.isEmpty) {
  console.log('No delegations found');
} else {
  console.log('Raw SCALE result:', result.toHex().slice(0, 80), '...');
}

await api.disconnect();
```

## Response Fields

- `delegate_ss58` (`AccountId32, required`): The delegate hotkey this account has staked with
- `take` (`Compact<u16>, required`): The delegate take stored as a normalized `u16` value
- `nominators` (`Vec<(AccountId32, Vec<(NetUid, stake)>)>, required`): Full nominator list for the delegate, grouped by subnet
- `owner_ss58` (`AccountId32, required`): The coldkey that owns the delegate hotkey
- `registrations` (`Vec<Compact<u16>>, required`): Subnet netuids where the delegate is registered
- `validator_permits` (`Vec<Compact<u16>>, required`): Subnet netuids where the delegate has validator permits
- `return_per_1000` (`Compact<u64>, required`): Estimated delegator return per 1000 TAO staked
- `total_daily_return` (`Compact<u64>, required`): Estimated total daily delegator return
- `netuid` / `alpha_stake` (`(u16, Compact<u64>), required`): The subnet identifier and this delegator's stake on that subnet

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "delegate_ss58": "<value>",
    "take": "<value>",
    "nominators": "<value>",
    "owner_ss58": "<value>",
    "registrations": "<value>",
    "validator_permits": "<value>",
    "return_per_1000": "<value>",
    "total_daily_return": "<value>",
    "netuid` / `alpha_stake": "<value>"
  }
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

### Error 5

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Replace with the coldkey bytes you want to inspect
coldkey_pubkey = [0] * 32

payload = {
    'jsonrpc': '2.0',
    'method': 'delegateInfo_getDelegated',
    'params': [coldkey_pubkey, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    print(f"SCALE byte count: {len(result['result'])}")
else:
    print('No delegations found for this account')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# delegated = sub.get_delegated(coldkey_ss58)
# for delegation in delegated:
#     print(f"Delegate: {delegation[0].hotkey_ss58}, Amount: {delegation[1]}")
```

### Full Python portfolio analysis

```python
import bittensor as bt

sub = bt.subtensor(network='finney')

coldkey_ss58 = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
delegations = sub.get_delegated(coldkey_ss58)

if not delegations:
    print(f"No delegations found for {coldkey_ss58}")
else:
    total_staked = 0
    total_daily_yield = 0

    print(f"Delegations for {coldkey_ss58[:18]}...\n")
    print(f"{'Delegate':<20} {'Staked (TAO)':>15} {'Take %':>8} {'Subnets':>10} {'Est. Daily':>12}")
    print("-" * 70)

    for delegate_info, staked_amount in delegations:
        staked_tao = staked_amount.tao
        take_pct = delegate_info.take * 100
        subnets = len(delegate_info.registrations)
        daily_return = delegate_info.total_daily_return.tao

        # Estimate your share of daily return
        if delegate_info.total_stake.tao > 0:
            your_share = (staked_tao / delegate_info.total_stake.tao) * daily_return * (1 - delegate_info.take)
        else:
            your_share = 0

        total_staked += staked_tao
        total_daily_yield += your_share

        print(f"{delegate_info.hotkey_ss58[:18]}.. {staked_tao:>14,.2f} {take_pct:>7.1f}% {subnets:>10} {your_share:>11,.4f}")

    print("-" * 70)
    print(f"{'Total':>20} {total_staked:>14,.2f} {'':>8} {'':>10} {total_daily_yield:>11,.4f}")
    print(f"\nEstimated annual yield: {total_daily_yield * 365:,.2f} TAO ({(total_daily_yield * 365 / total_staked * 100):.2f}%)")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const coldkey = '0x0000000000000000000000000000000000000000000000000000000000000000';
const result = await api.rpc.delegateInfo.getDelegated(coldkey);

if (result.isEmpty) {
  console.log('No delegations found');
} else {
  console.log('Raw SCALE result:', result.toHex().slice(0, 80), '...');
}

await api.disconnect();
```

### Historical delegation tracking

```python
import requests

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
coldkey_pubkey = '0x...'

# Get delegation state at two different blocks to track changes
block_hashes = [
    '0xabc...',  # earlier block
    '0xdef...',  # later block
]

for block_hash in block_hashes:
    payload = {
        'jsonrpc': '2.0',
        'method': 'delegateInfo_getDelegated',
        'params': [coldkey_pubkey, block_hash],
        'id': 1
    }
    response = requests.post(url, json=payload)
    result = response.json()
    print(f"Block {block_hash[:10]}...: {len(result.get('result', '')) // 2} bytes")
```

## Common Use Cases

- **Portfolio tracking** — Show a user all their active TAO delegations and the amount staked with each delegate.
- **Staking analytics** — Calculate total staked TAO, weighted average take rate, and estimated daily yield for a wallet.
- **Nomination monitoring** — Track which delegates an account has nominated and alert on changes (e.g., delegate deregistration).
- **Tax reporting** — Build delegation history by querying at sequential block hashes for staking income calculations.
- **Whale tracking** — Monitor large accounts' delegation patterns to understand network stake distribution.
- **Yield optimization** — Compare your current delegation spread against optimal allocation based on delegate performance metrics.

## Related Methods

- [`delegateInfo_getDelegates`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegates) — Get info for all registered delegates
- [`delegateInfo_getDelegate`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegate) — Get info for a single delegate by hotkey
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the metagraph for a subnet
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get configuration info for all subnets
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic subnet info including emission rates

---

## delegateInfo_getDelegates - Bittensor RPC Method

# delegateInfo_getDelegates - Bittensor RPC Method

## Overview

The `delegateInfo_getDelegates` method returns a SCALE-encoded byte array containing information about every registered delegate on the Bittensor network. Delegates are hotkeys that have registered to accept TAO stake from other accounts (nominators). This method is the primary way to discover all available delegates for staking decisions.

In Bittensor, delegation is a core economic mechanism. TAO holders who do not run their own validators can delegate their stake to a delegate hotkey and earn a share of the delegate's emissions. Each delegate sets a take rate (percentage of emissions they keep), making this data critical for yield optimization.

Delegates are distinct from regular validators in that they have explicitly opted in to accept external nominations. Not every validator is a delegate -- only those who have called the `become_delegate` extrinsic. The default take rate is 18% (1800 basis points), but delegates can adjust this between 0% and 100%. When evaluating delegates, consider both the take rate and the delegate's total emissions across subnets.

The data returned by this method includes each delegate's subnet registrations, allowing you to see which subnets a delegate is active on, which subnets they hold validator permits for, and how their stake and emissions are distributed.

## SCALE Decoding

The raw response is a JSON array of SCALE bytes that must be decoded before use. There are two main approaches:

**Using `@polkadot/api` (JavaScript/TypeScript):** Register Bittensor custom types before creating the API instance. The Bittensor node exposes its type definitions through the RPC metadata. In practice, define a local type bundle or custom registry entry for `DelegateInfo`, then decode the payload as `Vec<DelegateInfo>` with `createType` or `registry.createType`.

**Using `scalecodec` (Python):** The `bittensor` Python SDK wraps SCALE decoding internally. If you need manual decoding, use the `scalecodec` library with a Bittensor-specific type registry that defines `DelegateInfo` as a struct containing the fields listed above.

**Key decoding notes:**

- The `take` field uses basis points: divide by 10000 to get a percentage (e.g., `1800` = 18%)
- Stake amounts in `nominators` are in RAO: divide by `1e9` to convert to TAO
- The `return_per_1000` field is also in RAO and represents estimated yield per 1000 TAO staked over a period
- `registrations` and `validator_permits` contain subnet netuid values (u16)
- The `nominators` list can be very large for popular delegates (thousands of entries), which is the main driver of response size
- `validator_permits` is a subset of `registrations` -- a delegate can be registered on a subnet without having a validator permit if they do not have enough stake to qualify
- The `owner_ss58` field is the coldkey that controls the delegate hotkey. This is important for identifying the operator behind a delegate
- `total_daily_return` is an estimate based on recent emission history and may fluctuate between tempos

## Code Examples

### Using SubstrateExamples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "delegateInfo_getDelegates",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `delegate_ss58` (`AccountId32, required`): The delegate's hotkey SS58 address
- `take` (`Compact<u16>, required`): Delegate's take rate (percentage of emissions retained, in basis points). Default is `1800` (18%). Range: 0--10000
- `nominators` (`Vec<(AccountId32, Compact<u64>)>, required`): List of nominator accounts and their staked amounts (in RAO, where 1 TAO = 10^9 RAO)
- `owner_ss58` (`AccountId32, required`): The coldkey that owns this delegate hotkey
- `registrations` (`Vec<Compact<u16>>, required`): Subnet netuids where this delegate is registered
- `validator_permits` (`Vec<Compact<u16>>, required`): Subnet netuids where this delegate has validator permits
- `return_per_1000` (`Compact<u64>, required`): Estimated return per 1000 TAO staked (in RAO)
- `total_daily_return` (`Compact<u64>, required`): Total daily emissions earned by this delegate (in RAO)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "delegate_ss58": "<value>",
    "take": "<value>",
    "nominators": "<value>",
    "owner_ss58": "<value>",
    "registrations": "<value>",
    "validator_permits": "<value>",
    "return_per_1000": "<value>",
    "total_daily_return": "<value>"
  }
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

### Error 5

### Error 6

### Decode with Python (bittensor SDK)

```python
import requests
import json

# Query all delegates via JSON-RPC
url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
payload = {
    'jsonrpc': '2.0',
    'method': 'delegateInfo_getDelegates',
    'params': [],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

# The result is a JSON array of SCALE bytes
scale_bytes = result['result']
print(f'Response size: {len(scale_bytes)} bytes')

# To decode, use the bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# delegates = sub.get_delegates()
# for d in delegates[:5]:
#     print(f"Delegate: {d.hotkey_ss58}, Take: {d.take}, Nominators: {len(d.nominators)}")
```

### Full Python example with analysis

```python
import bittensor as bt

sub = bt.subtensor(network='finney')
delegates = sub.get_delegates()

# Sort delegates by total stake (descending)
delegates_sorted = sorted(delegates, key=lambda d: d.total_stake, reverse=True)

# Display top 10 delegates
print(f"{'Hotkey':<20} {'Take %':>8} {'Nominators':>12} {'Total Stake (TAO)':>20}")
print("-" * 64)
for d in delegates_sorted[:10]:
    take_pct = d.take * 100
    total_tao = d.total_stake.tao
    print(f"{d.hotkey_ss58[:18]}.. {take_pct:>7.1f}% {len(d.nominators):>12} {total_tao:>20,.2f}")

# Calculate network-wide delegation statistics
total_delegated = sum(d.total_stake.tao for d in delegates)
avg_take = sum(d.take for d in delegates) / len(delegates) * 100
print(f"\nTotal delegates: {len(delegates)}")
print(f"Total TAO delegated: {total_delegated:,.2f}")
print(f"Average take rate: {avg_take:.1f}%")
```

### Decode with JavaScript (@polkadot/api)

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call the custom RPC method
const result = await api.rpc.delegateInfo.getDelegates();

// The result is SCALE-encoded; decode with Bittensor type registry
// Register Bittensor types before creating the API instance for automatic decoding
console.log('Raw SCALE result length:', result.length);

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "delegateInfo_getDelegates",
    "params": [],
    "id": 1
  }'
```

ze considerations:\*\* On mainnet with hundreds of active delegates, each with potentially thousands of nominators, the response can exceed 5 MB. Plan your HTTP client buffer sizes and parsing strategy accordingly. For bandwidth-constrained environments, consider querying individual delegates via `delegateInfo_getDelegate` instead.

## Common Use Cases

- **Staking dashboards** — Display all available delegates with their take rates, total stake, and nominator counts so users can choose where to delegate TAO.
- **Delegate discovery** — Help new TAO holders find active, well-performing delegates across different subnets.
- **Yield analysis** — Compare delegate returns, take rates, and historical performance to optimize staking yield. Use `return_per_1000` to estimate annualized yields.
- **Network analytics** — Track total delegation across the network, concentration of stake, and delegate activity. Identify the Nakamoto coefficient for delegation.
- **Validator monitoring** — Monitor which subnets delegates are registered on and whether they hold validator permits. Alert when delegates lose permits.
- **Subnet coverage analysis** — Identify which subnets have the most delegate coverage and which are underserved by comparing `registrations` across all delegates.
- **Take rate alerts** — Monitor delegate take rates for changes. A delegate lowering their take may signal increased competition for nominations; a raise may indicate reduced yield for nominators.
- **Nominator concentration** — Analyze the distribution of stake across nominators for each delegate. High concentration (few large nominators) versus wide distribution affects risk for smaller stakers.
- **Historical snapshots** — While this method does not accept a block hash parameter directly, you can use it alongside `chain_getBlockHash` and block-specific queries to reconstruct delegate state over time.

## Related Methods

- [`delegateInfo_getDelegate`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegate) — Get info for a single delegate by hotkey (lighter than fetching all)
- [`delegateInfo_getDelegated`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegated) — Get delegations made by a specific coldkey account
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the metagraph for a subnet (includes validator/miner data)
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get configuration info for all subnets (complements delegate data)
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic subnet economics (emissions that delegates earn)
- [`neuronInfo_getNeuron`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuron) — Get detailed neuron info by UID within a subnet
- [`swap_currentAlphaPrice`](https://www.dwellir.com/docs/bittensor/swap_currentAlphaPrice) — Get the current alpha token price for a subnet

---

## eth_accounts - Bittensor RPC Method

# eth_accounts - Bittensor RPC Method

Returns a list of addresses owned by the client on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for AI/ML developers, subnet operators, and teams building decentralized machine learning applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/bittensor/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/bittensor/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Bittensor RPC Method

# eth_blockNumber - Bittensor RPC Method

Returns the number of the most recent block on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_blockNumber` is fundamental for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Syncing Applications** - Keep your dApp in sync with the latest Bittensor blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Bittensor block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Bittensor block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Bittensor block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Bittensor block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Bittensor block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Bittensor:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Bittensor:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Bittensor node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bittensor/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/bittensor/eth_syncing) - Check if node is still syncing

---

## eth_call - Bittensor RPC Method

# eth_call - Bittensor RPC Method

Executes a new message call immediately without creating a transaction on Bittensor. Used for reading smart contract state.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

The `eth_call` method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Bittensor
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';
const walletAddress = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Bittensor. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Bittensor
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Bittensor

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "data": "0x70a08231000000000000000000000000156e431cc96e0e3b70c97214d869c9bc4b5bbd21"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "data": "0x70a08231000000000000000000000000156e431cc96e0e3b70c97214d869c9bc4b5bbd21"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
    '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    data := common.FromHex("0x70a08231000000000000000000000000156e431cc96e0e3b70c97214d869c9bc4b5bbd21")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/bittensor/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Bittensor RPC Method

# eth_chainId - Bittensor RPC Method

Returns the chain ID used for transaction signing on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_chainId` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/bittensor/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/bittensor/eth_syncing) - Check sync status

---

## eth_coinbase - Bittensor RPC Method

# eth_coinbase - Bittensor RPC Method

Checks the legacy `eth_coinbase` compatibility method on Bittensor. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for AI/ML developers, subnet operators, and teams building decentralized machine learning applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Bittensor coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Bittensor coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Bittensor coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Bittensor coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Bittensor coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Bittensor nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/bittensor/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/bittensor/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/bittensor/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Bittensor RPC Method

# eth_estimateGas - Bittensor RPC Method

Estimates the gas necessary to execute a transaction on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Bittensor
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Bittensor.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Bittensor may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "to": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "to": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/bittensor/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Bittensor RPC Method

# eth_feeHistory - Bittensor RPC Method

Returns historical gas fee data on Bittensor, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Bittensor without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Bittensor.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Bittensor) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/bittensor/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/bittensor/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/bittensor/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Bittensor RPC Method

# eth_gasPrice - Bittensor RPC Method

Returns the current gas price on Bittensor in wei.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Bittensor
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Bittensor. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Bittensor, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Bittensor: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Bittensor supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/bittensor/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/bittensor/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/bittensor/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Bittensor RPC Method

# eth_getBalance - Bittensor RPC Method

Returns the balance of a given address on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getBalance` is fundamental for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Bittensor
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Bittensor
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Bittensor. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Bittensor`);
  return balance;
}

displayBalance('0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Bittensor at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Bittensor')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Bittensor')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Bittensor.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/bittensor/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/bittensor/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Bittensor RPC Method

# eth_getBlockByHash - Bittensor RPC Method

Returns information about a block by hash on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getBlockByHash` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Bittensor
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Bittensor.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Bittensor.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/bittensor/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Bittensor RPC Method

# eth_getBlockByNumber - Bittensor RPC Method

Returns information about a block by block number on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getBlockByNumber` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Bittensor
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Bittensor with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Bittensor. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/bittensor/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bittensor/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bittensor/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Bittensor RPC Method

# eth_getBlockReceipts - Bittensor RPC Method

Returns all transaction receipts for a block on Bittensor. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getBlockReceipts` is useful for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Bittensor, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Bittensor. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xbdee85c3ba64aa4a13d1bc6766b22e4f1baba2268fc1f9fbab5e4d52d85edb41",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bittensor/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bittensor/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Bittensor RPC Method

# eth_getCode - Bittensor RPC Method

Returns the bytecode at a given address on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getCode` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Bittensor
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Bittensor:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Bittensor:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/bittensor/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/bittensor/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Bittensor RPC Method

# eth_getFilterChanges - Bittensor RPC Method

Polls a filter on Bittensor for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getFilterChanges` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Bittensor
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Bittensor:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bittensor/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/bittensor/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/bittensor/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bittensor/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/bittensor/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Bittensor RPC Method

# eth_getFilterLogs - Bittensor RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Bittensor. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getFilterLogs` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Bittensor
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bittensor/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bittensor/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/bittensor/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bittensor/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Bittensor RPC Method

# eth_getLogs - Bittensor RPC Method

Returns an array of all logs matching a given filter object on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Bittensor for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Bittensor
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Bittensor.

```javascript
const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Bittensor enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Bittensor, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bittensor/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bittensor/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Bittensor RPC Method

# eth_getStorageAt - Bittensor RPC Method

Returns the value from a storage position at a given address on Bittensor. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getStorageAt` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **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 AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **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": [
    "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "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-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', '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-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';

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-bittensor-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 = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
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-bittensor-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-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    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 Bittensor:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-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-bittensor-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 = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';
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 Bittensor:`);
  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/bittensor/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/bittensor/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/bittensor/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Bittensor RPC Method

# eth_getTransactionByHash - Bittensor RPC Method

Returns the information about a transaction by transaction hash on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getTransactionByHash` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Bittensor
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Bittensor. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Bittensor. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bittensor/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Bittensor RPC Method

# eth_getTransactionCount - Bittensor RPC Method

Returns the number of transactions sent from an address on Bittensor, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getTransactionCount` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Bittensor
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Bittensor nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21'
nonce = get_transaction_count(address)
print(f'Bittensor nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Bittensor nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Bittensor:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/bittensor/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bittensor/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bittensor/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Bittensor RPC Method

# eth_getTransactionReceipt - Bittensor RPC Method

Returns the receipt of a transaction by transaction hash on Bittensor. Receipt is only available for mined transactions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_getTransactionReceipt` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Bittensor and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Bittensor. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Bittensor, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xb39db715c7f2ea113073175f071afe67a2c809bd30694c1a768d970ed159a1d7")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bittensor/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/bittensor/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Bittensor RPC Method

# eth_hashrate - Bittensor RPC Method

Returns the legacy `eth_hashrate` compatibility value on Bittensor. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Bittensor hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Bittensor hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Bittensor hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Bittensor hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Bittensor hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/bittensor/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/bittensor/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/bittensor/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Bittensor RPC Method

# eth_maxPriorityFeePerGas - Bittensor RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Bittensor. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Bittensor
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Bittensor priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Bittensor priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Bittensor priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Bittensor:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Bittensor:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/bittensor/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/bittensor/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/bittensor/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bittensor/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Bittensor RPC Method

# eth_mining - Bittensor RPC Method

Checks the legacy `eth_mining` compatibility method on Bittensor. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Bittensor mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Bittensor mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Bittensor mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Bittensor mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Bittensor mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/bittensor/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/bittensor/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/bittensor/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Bittensor RPC Method

# eth_newBlockFilter - Bittensor RPC Method

Creates a filter on Bittensor that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_newBlockFilter` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Block Monitoring** - Detect new blocks on Bittensor as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Bittensor:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bittensor/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bittensor/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/bittensor/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bittensor/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Bittensor RPC Method

# eth_newFilter - Bittensor RPC Method

Creates a filter object on Bittensor based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_newFilter` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Event Monitoring** - Subscribe to specific contract events on Bittensor such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Bittensor:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bittensor/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/bittensor/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/bittensor/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bittensor/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/bittensor/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Bittensor RPC Method

# eth_newPendingTransactionFilter - Bittensor RPC Method

Creates a filter on Bittensor that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on Bittensor to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Bittensor...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Bittensor:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bittensor/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bittensor/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bittensor/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Bittensor RPC Method

# eth_protocolVersion - Bittensor RPC Method

Returns the current Ethereum protocol version used by the Bittensor node.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_protocolVersion` is useful for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Current Dwellir Result

Dwellir's shared Bittensor EVM endpoint currently returns the integer-compatible value `1` from `eth_protocolVersion`. Treat that value as a simple compatibility signal for this surface instead of assuming the response is always a hex string.

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`INTEGER, required`): Integer-compatible protocol version value. Dwellir's shared Bittensor endpoint currently returns 1.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 1
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1,
  }),
});

const { result } = await response.json();
const version = typeof result === 'string' ? Number(result) : result;

console.log('Bittensor protocol version:', version);
```

```python
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_protocolVersion',
        'params': [],
        'id': 1,
    },
)

result = response.json()['result']
version = int(result)
print(f'Bittensor protocol version: {version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result int
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Bittensor protocol version: %d\n", result)
}
```

## Common Use Cases

### 1. Gate compatibility checks on the raw value

```javascript
async function assertBittensorProtocol(provider) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = typeof result === 'string' ? Number(result) : result;

  if (version !== 1) {
    throw new Error(`Unexpected Bittensor protocol version: ${version}`);
  }

  return version;
}
```

### 2. Record client/version pairs across a fleet

```javascript
async function auditBittensorNodes(provider) {
  const [protocolVersion, clientVersion] = await Promise.all([
    provider.send('eth_protocolVersion', []),
    provider.send('web3_clientVersion', []),
  ]);

  return {
    protocolVersion: typeof protocolVersion === 'string' ? Number(protocolVersion) : protocolVersion,
    clientVersion,
  };
}
```

### 3. Normalize mixed-client protocol responses

```python
def normalize_protocol_version(value) -> int:
    if isinstance(value, str):
        return int(value, 0)

    return int(value)
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/bittensor/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/bittensor/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/bittensor/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Bittensor RPC Method

# eth_sendRawTransaction - Bittensor RPC Method

Submits a pre-signed transaction for broadcast to Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Bittensor
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Bittensor mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/bittensor/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/bittensor/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/bittensor/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bittensor/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Bittensor RPC Method

# eth_sendTransaction - Bittensor RPC Method

Creates and sends a new transaction from an unlocked account on Bittensor. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for AI/ML developers, subnet operators, and teams building decentralized machine learning applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Bittensor tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Bittensor tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Bittensor tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Bittensor tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Bittensor tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Bittensor dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/bittensor/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/bittensor/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Bittensor RPC Method

# eth_signTransaction - Bittensor RPC Method

Signs a transaction with the private key of the specified account on Bittensor without submitting it to the network.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for AI/ML developers, subnet operators, and teams building decentralized machine learning applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Bittensor tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Bittensor tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Bittensor tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Bittensor:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/bittensor/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/bittensor/eth_accounts) - List accounts available for signing

---

## eth_syncing - Bittensor RPC Method

# eth_syncing - Bittensor RPC Method

Returns the sync status of your Bittensor node - either `false` when fully synced, or an object describing the sync progress.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_syncing` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Bittensor node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Bittensor node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Bittensor node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/bittensor/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/bittensor/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/bittensor/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/bittensor/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Bittensor RPC Method

# eth_uninstallFilter - Bittensor RPC Method

Removes a filter on Bittensor that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`eth_uninstallFilter` is important for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bittensor/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/bittensor/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/bittensor/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bittensor/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/bittensor/eth_getFilterLogs) - Get all logs matching a filter

---

## grandpa_roundState - Bittensor RPC Method

# grandpa_roundState - Bittensor RPC Method

Returns the state of the current GRANDPA finality round on Bittensor when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`grandpa_roundState` is not currently exposed on Dwellir's public Bittensor RPC. If you need finality status for production monitoring, use [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) for the latest finalized block hash or [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) to stream finalized heads as they arrive.

- **Finalized block tracking** -- Use `chain_getFinalizedHead` to snapshot the current finalized head
- **Realtime finality updates** -- Use `chain_subscribeFinalizedHeads` when your service needs push-based finalized-head updates
- **Operational monitoring** -- Prefer finalized-head health checks over validator-round internals on the shared endpoint

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

```javascript
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1,
  }),
});

const payload = await response.json();
console.log(payload.error);
// { code: -32601, message: 'Method not found' }
```

```python
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'grandpa_roundState',
        'params': [],
        'id': 1,
    },
)

print(response.json()['error'])
# {'code': -32601, 'message': 'Method not found'}
```

## Supported Alternatives

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) for the latest finalized block hash
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) for streamed finalized-head updates

## Supported Monitoring Patterns

Because Dwellir's public Bittensor endpoint does not expose `grandpa_roundState`, build finalized-head monitoring around the supported RPCs below.

### 1. Snapshot the latest finalized head

Use `chain_getFinalizedHead` when you want the current finalized block hash on demand:

```javascript
async function getLatestFinalizedHead(api) {
  const finalizedHead = await api.rpc.chain.getFinalizedHead();
  return finalizedHead.toHex();
}
```

### 2. Stream finalized heads in real time

Subscribe to finalized-head updates when your service needs push-based finality signals:

```javascript
async function subscribeFinalizedHeads(api) {
  return api.rpc.chain.subscribeFinalizedHeads((header) => {
    console.log(`Finalized block #${header.number.toString()} (${header.hash.toHex()})`);
  });
}
```

### 3. Measure finalized lag against the best block

Compare the latest finalized head with the newest block header to track confirmation lag:

```javascript
async function getFinalityLag(api) {
  const [finalizedHash, bestHeader] = await Promise.all([
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader(),
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  return {
    bestBlock: bestHeader.number.toNumber(),
    finalizedBlock: finalizedHeader.number.toNumber(),
    lagBlocks: bestHeader.number.toNumber() - finalizedHeader.number.toNumber(),
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/bittensor/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/bittensor/system_health) -- Check overall node health including sync and peer status

---

## net_listening - Bittensor RPC Method

# net_listening - Bittensor RPC Method

Checks whether the connected Bittensor client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`net_listening` is useful for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Bittensor node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Bittensor node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Bittensor node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/bittensor/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/bittensor/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/bittensor/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/bittensor/web3_clientVersion) - Get node client info

---

## net_peerCount - Bittensor RPC Method

# net_peerCount - Bittensor RPC Method

Returns the number of peers currently connected to your Bittensor node.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`net_peerCount` is important for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Bittensor deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Bittensor peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Bittensor peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Bittensor peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Bittensor nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/bittensor/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/bittensor/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/bittensor/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/bittensor/web3_clientVersion) - Get node client info

---

## net_version - Bittensor RPC Method

# net_version - Bittensor RPC Method

Returns the current network ID on Bittensor as a decimal string. The network ID identifies which network the node is connected to.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`net_version` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Endpoint Identification** - Confirm your application is connected to the expected Bittensor network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Bittensor network ID:', networkId);

// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Bittensor network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Bittensor network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/bittensor/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/bittensor/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/bittensor/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/bittensor/eth_syncing) - Check node sync progress

---

## neuronInfo_getNeuron - Bittensor RPC Method

# neuronInfo_getNeuron - Bittensor RPC Method

## Overview

The `neuronInfo_getNeuron` method returns SCALE-encoded detailed information for a specific neuron identified by its UID within a Bittensor subnet. Every participant in a subnet -- whether a validator or a miner -- is a "neuron" with a unique UID assigned at registration time.

This method returns comprehensive data about a single neuron: its identity (hotkey/coldkey), stake, performance scores (trust, consensus, incentive, dividends), emission earnings, axon endpoint, and weight/bond information. It is the most detailed single-neuron query available.

Use this method when you need to inspect a specific neuron's state -- for example, after looking up a UID in the metagraph and wanting the full detail view.

## SCALE Decoding

The response decodes to a `NeuronInfo` struct using Bittensor's custom type registry.

**Using `@polkadot/api`:** Register the following types:

- `NeuronInfo`: The main neuron struct with all fields listed above
- `AxonInfo`: Contains `version` (u32), `ip` (u128), `port` (u16), `ip_type` (u8), `protocol` (u8), `placeholder1` (u8), `placeholder2` (u8)
- `PrometheusInfo`: Contains `version` (u32), `ip` (u128), `port` (u16), `ip_type` (u8)

**Using `bittensor` Python SDK:** Use `sub.neuron_for_uid(uid=N, netuid=M)` which returns a `NeuronInfo` namedtuple with all fields decoded and converted to human-readable formats.

**Key decoding notes:**

- All u16 score fields are scaled 0--65535. Divide by 65535 for float values (0.0--1.0)
- The `stake` field is a vector of staking entries. Sum the decoded amounts if you need a total stake figure.
- `emission` is in RAO per tempo. To get TAO per day: `(emission / 1e9) * (7200 / tempo)` where tempo is the subnet's block interval
- IP addresses in `axon_info` and `prometheus_info` are stored as u128. For IPv4, convert the 4 least significant bytes
- `weights` is a sparse vector: only non-zero weight assignments are included

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `netuid` (`u16, required`): The subnet identifier
- `uid` (`u16, required`): The neuron's unique identifier within the subnet
- `at` (`BlockHash, optional`): Optional block hash to query at a specific block. Pass `null` for the latest state

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "neuronInfo_getNeuron",
    "params": [1, 0, null],
    "id": 1
  }'
```

## Response Fields

- `hotkey` (`AccountId32, required`): The neuron's hotkey address (identifies the neuron on-chain)
- `coldkey` (`AccountId32, required`): The neuron's coldkey (owner) address
- `uid` (`u16, required`): Neuron UID within the subnet
- `netuid` (`u16, required`): The subnet identifier
- `active` (`bool, required`): Whether the neuron is currently active
- `stake` (`Vec<(AccountId32, Compact<u64>)>, required`): Stake entries associated with the neuron on the queried subnet
- `rank` (`u16, required`): Neuron's rank score (0--65535 scaled)
- `emission` (`u64, required`): Emissions earned per tempo (RAO). Divide by 1e9 for TAO
- `incentive` (`u16, required`): Incentive score (0--65535 scaled). Higher = better-performing miner
- `consensus` (`u16, required`): Consensus score (0--65535 scaled). Reflects agreement among validators
- `trust` (`u16, required`): Trust score (0--65535 scaled). Measures how much other neurons trust this one
- `validator_trust` (`u16, required`): Validator-specific trust score (how much other validators trust this one)
- `dividends` (`u16, required`): Dividend score (0--65535 scaled). Higher = more validator reward share
- `last_update` (`u64, required`): Last block this neuron set weights
- `validator_permit` (`bool, required`): Whether this neuron has a validator permit
- `weights` (`Vec<(u16, u16)>, required`): Weight assignments to other neurons (target_uid, weight)
- `bonds` (`Vec<(u16, u16)>, required`): Bond assignments (target_uid, bond_amount)
- `axon_info` (`AxonInfo, required`): Network endpoint (IP, port, protocol version)
- `prometheus_info` (`PrometheusInfo, required`): Prometheus metrics endpoint (IP, port)
- `pruning_score` (`u16, required`): Score used to determine deregistration priority (lower = more likely to be pruned)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hotkey": "<value>",
    "coldkey": "<value>",
    "uid": "<value>",
    "netuid": "<value>",
    "active": true,
    "stake": "<value>",
    "rank": "<value>",
    "emission": "<value>",
    "incentive": "<value>",
    "consensus": "<value>",
    "trust": "<value>",
    "validator_trust": "<value>",
    "dividends": "<value>",
    "last_update": "<value>",
    "validator_permit": true,
    "weights": "<value>",
    "bonds": "<value>",
    "axon_info": "<value>",
    "prometheus_info": "<value>",
    "pruning_score": "<value>"
  }
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

### Error 5

### Error 6

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Fetch neuron info for UID 0 in subnet 1
payload = {
    'jsonrpc': '2.0',
    'method': 'neuronInfo_getNeuron',
    'params': [1, 0, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'Neuron info SCALE data size: {len(scale_bytes)} bytes')
else:
    print('No neuron found at this UID')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# neuron = sub.neuron_for_uid(uid=0, netuid=1)
# print(f"Hotkey: {neuron.hotkey}")
# print(f"Stake: {neuron.stake:.4f} TAO")
# print(f"Trust: {neuron.trust:.4f}")
# print(f"Incentive: {neuron.incentive:.4f}")
# print(f"Emission: {neuron.emission:.4f} TAO/tempo")
```

### Full Python neuron analysis

```python
import bittensor as bt
import socket
import struct

sub = bt.subtensor(network='finney')

# Detailed neuron inspection
netuid = 1
uid = 0
neuron = sub.neuron_for_uid(uid=uid, netuid=netuid)

print(f"=== Neuron UID {uid} on Subnet {netuid} ===")
print(f"Hotkey:  {neuron.hotkey}")
print(f"Coldkey: {neuron.coldkey}")
print(f"Active:  {neuron.active}")

# Role identification
role = "Validator" if neuron.validator_permit else "Miner"
print(f"Role:    {role}")

# Performance scores
print(f"\n--- Performance ---")
print(f"Trust:           {neuron.trust:.4f}")
print(f"Consensus:       {neuron.consensus:.4f}")
print(f"Incentive:       {neuron.incentive:.4f}")
print(f"Dividends:       {neuron.dividends:.4f}")
print(f"Rank:            {neuron.rank:.4f}")
print(f"Validator Trust: {neuron.validator_trust:.4f}")
print(f"Pruning Score:   {neuron.pruning_score:.4f}")

# Stake breakdown
print(f"\n--- Stake ---")
total_stake = sum(amount.tao for _, amount in neuron.stake)
print(f"Total stake: {total_stake:,.2f} TAO ({len(neuron.stake)} stake entries)")
for coldkey, amount in sorted(neuron.stake, key=lambda x: x[1], reverse=True)[:5]:
    pct = (amount.tao / total_stake * 100) if total_stake > 0 else 0
    print(f"  {coldkey[:18]}.. : {amount.tao:>12,.2f} TAO ({pct:.1f}%)")

# Emissions
print(f"\n--- Emissions ---")
print(f"Emission per tempo: {neuron.emission:.6f} TAO")

# Weight analysis (for validators)
if neuron.validator_permit and neuron.weights:
    print(f"\n--- Weights (top 10) ---")
    sorted_weights = sorted(neuron.weights, key=lambda x: x[1], reverse=True)
    for target_uid, weight in sorted_weights[:10]:
        print(f"  -> UID {target_uid}: weight={weight / 65535:.4f}")

# Network endpoint
if neuron.axon_info.ip != 0:
    ip_bytes = neuron.axon_info.ip.to_bytes(16, 'big')
    ip_str = socket.inet_ntoa(ip_bytes[-4:])
    print(f"\n--- Axon Endpoint ---")
    print(f"IP: {ip_str}:{neuron.axon_info.port}")
    print(f"Version: {neuron.axon_info.version}")

# Last activity
current_block = sub.block
blocks_since_update = current_block - neuron.last_update
minutes_since = blocks_since_update * 12 / 60
print(f"\n--- Activity ---")
print(f"Last weight update: block {neuron.last_update} ({blocks_since_update} blocks / ~{minutes_since:.0f} min ago)")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Fetch neuron info for UID 0 in subnet 1
const neuronInfo = await api.rpc.neuronInfo.getNeuron(1, 0);
console.log('Raw data size:', neuronInfo.toHex().length, 'bytes');

// With Bittensor types registered:
// console.log('Hotkey:', neuronInfo.hotkey.toHuman());
// console.log('Active:', neuronInfo.active.toString());
// console.log('Emission:', neuronInfo.emission.toString());
// console.log('Validator permit:', neuronInfo.validator_permit.toString());

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "neuronInfo_getNeuron",
    "params": [1, 0, null],
    "id": 1
  }'
```

### Historical performance tracking

```python
import requests

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Query neuron state at multiple past blocks to track performance
netuid = 1
uid = 42
block_hashes = ['0xabc...', '0xdef...', '0x123...']  # Past block hashes

for i, block_hash in enumerate(block_hashes):
    payload = {
        'jsonrpc': '2.0',
        'method': 'neuronInfo_getNeuron',
        'params': [netuid, uid, block_hash],
        'id': i + 1
    }
    response = requests.post(url, json=payload)
    result = response.json()
    if result.get('result'):
        print(f"Block {block_hash[:10]}...: {len(result['result']) // 2} bytes")
    # Decode each snapshot to track score changes over time
```

ze via `subnetInfo_getMetagraph` before querying |
\| Deregistered neuron | Decodes to a low-signal or placeholder neuron payload depending on runtime tooling | Cross-check the UID against the current metagraph before treating the record as active |
\| Invalid block hash | Returns JSON-RPC error | Verify block hash exists |
\| Node not synced | May return stale neuron data | Check `system_health` |
\| Rate limit exceeded | HTTP 429 | Cache neuron data; refresh once per tempo |

## Common Use Cases

- **Miner monitoring** — Track a miner's incentive score, rank, emission earnings, and active status over time.
- **Validator monitoring** — Monitor a validator's trust, consensus scores, and weight-setting frequency.
- **Performance tracking** — Compare a neuron's scores across blocks to detect performance trends or anomalies.
- **Axon discovery** — Look up a neuron's network endpoint (IP/port) for direct communication.
- **Staking decisions** — Inspect a neuron's stake distribution, validator permit status, and trust before delegating.
- **Explorer views** — Build neuron detail pages showing all attributes for a specific participant.
- **Pruning risk assessment** — Monitor the pruning score to anticipate potential deregistration.
- **Weight auditing** — Inspect a validator's weight assignments to verify they are evaluating miners correctly.

## Related Methods

- [`neuronInfo_getNeurons`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeurons) — Get detailed info for all neurons in a subnet
- [`neuronInfo_getNeuronLite`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuronLite) — Get lightweight neuron info (fewer fields, smaller payload)
- [`neuronInfo_getNeuronsLite`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuronsLite) — Get lightweight info for all neurons
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the full metagraph for a subnet
- [`subnetInfo_getSelectiveMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSelectiveMetagraph) — Get metagraph data for specific UIDs
- [`delegateInfo_getDelegate`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegate) — Get delegate info if this neuron is a delegate

---

## neuronInfo_getNeuronLite - JSON-RPC Method

# neuronInfo_getNeuronLite - JSON-RPC Method

## Description

Bittensor neuron information (lite and detailed) per subnet, including UIDs and attributes. Use to index participants and build explorer views.

Returns compact neuron info for a single neuron (uid) in a subnet.

## Code Examples

## Request Parameters

- `netuid` (`INTEGER, required`): Subnet identifier.
- `uid` (`INTEGER, required`): Neuron UID within the subnet.
- `at` (`DATA, optional`): Optional block hash to query state at.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "neuronInfo_getNeuronLite",
    "params": [1, 0, null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded lite neuron info.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x11223344"
}
```

---

## neuronInfo_getNeurons - JSON-RPC Method

# neuronInfo_getNeurons - JSON-RPC Method

## Description

Bittensor neuron information (lite and detailed) per subnet, including UIDs and attributes. Use to index participants and build explorer views.

Returns detailed neuron info for all neurons in a subnet.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `at` (`string, optional`): Optional block hash to query historical neuron state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "neuronInfo_getNeurons",
  "params": [
    1,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded neuron records for the requested subnet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    1,
    4,
    184,
    125
  ]
}
```

---

## neuronInfo_getNeuronsLite - JSON-RPC Method

# neuronInfo_getNeuronsLite - JSON-RPC Method

## Description

Bittensor neuron information (lite and detailed) per subnet, including UIDs and attributes. Use to index participants and build explorer views.

Returns compact neuron info for all neurons in a subnet.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `at` (`string, optional`): Optional block hash to query historical neuron state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "neuronInfo_getNeuronsLite",
  "params": [
    1,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded compact neuron data for the requested subnet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    1,
    4,
    184,
    125
  ]
}
```

---

## offchain_localStorageClear - Bittensor RPC Method

# offchain_localStorageClear - Bittensor RPC Method

Removes a key from the node's offchain local storage. Offchain local storage is a node-local key-value store used by offchain workers and is not shared across the network or stored on-chain. This is an administrative method that requires the node to be running with `--rpc-methods unsafe` and is not available on public shared RPC endpoints.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "offchain_localStorageClear",
    "params": [],
    "id": 1
  }'
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Use Cases

- **Offchain worker reset** -- Clear cached or stale offchain data that an offchain worker relies on, forcing it to re-fetch from external sources.
- **Development and testing** -- Reset offchain state during development or debugging of offchain worker logic.
- **Storage cleanup** -- Remove obsolete entries from offchain storage on a self-hosted Bittensor node.

## Notes

- This is an unsafe/administrative method. It is disabled on public RPC endpoints including Dwellir's shared Bittensor nodes.
- Offchain storage is local to each node and is not part of the blockchain state.
- The `PERSISTENT` kind survives node restarts; `LOCAL` kind is cleared when the node restarts.

## Related Methods

- [`offchain_localStorageGet`](https://www.dwellir.com/docs/bittensor/offchain_localStorageGet) -- Read a value from offchain local storage
- [`offchain_localStorageSet`](https://www.dwellir.com/docs/bittensor/offchain_localStorageSet) -- Write a value to offchain local storage

---

## offchain_localStorageGet - Bittensor RPC Method

# offchain_localStorageGet - Bittensor RPC Method

Reads a value from the node's offchain local storage by key. Offchain local storage is a node-local key-value store used by offchain workers for caching data, tracking state, or communicating between offchain worker runs. This data is not stored on-chain and is specific to each node.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "offchain_localStorageGet",
    "params": [],
    "id": 1
  }'
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Use Cases

- **Offchain worker debugging** -- Inspect values stored by offchain workers to verify correct behavior.
- **State inspection** -- Read cached external data (e.g. oracle prices, API responses) that offchain workers have stored locally.
- **Monitoring** -- Check whether offchain workers are running and updating their local state.

## Notes

- On public RPC endpoints (including Dwellir's shared Bittensor nodes), offchain storage access is usually disabled. Expect `null` or an error.
- Offchain storage is local to each node. Two nodes running the same chain will have different offchain storage contents.
- The `PERSISTENT` kind survives node restarts; `LOCAL` kind is ephemeral.

## Related Methods

- [`offchain_localStorageSet`](https://www.dwellir.com/docs/bittensor/offchain_localStorageSet) -- Write a value to offchain local storage
- [`offchain_localStorageClear`](https://www.dwellir.com/docs/bittensor/offchain_localStorageClear) -- Remove a key from offchain local storage

---

## offchain_localStorageSet - Bittensor RPC Method

# offchain_localStorageSet - Bittensor RPC Method

Writes a key-value pair to the node's offchain local storage. Offchain local storage is a node-local key-value store used by offchain workers and is not shared across the network or stored on-chain. This is an administrative method that requires the node to be running with `--rpc-methods unsafe`.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "offchain_localStorageSet",
    "params": [],
    "id": 1
  }'
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Use Cases

- **Offchain worker configuration** -- Pre-load configuration or seed data for offchain workers on a self-hosted Bittensor node.
- **Testing and development** -- Inject test data into offchain storage for developing and debugging offchain worker logic.
- **External data caching** -- Store external API responses or oracle data that offchain workers can use in subsequent runs.

## Notes

- This is an unsafe/administrative method. It is disabled on public RPC endpoints including Dwellir's shared Bittensor nodes.
- In live checks on Dwellir-hosted public Bittensor endpoints, the call returns `-32601 RPC call is unsafe to be called externally`.
- Offchain storage is local to each node and is not replicated across the network.
- The `PERSISTENT` kind survives node restarts; `LOCAL` kind is cleared when the node restarts.
- Both key and value must be hex-encoded with a `0x` prefix.

## Related Methods

- [`offchain_localStorageGet`](https://www.dwellir.com/docs/bittensor/offchain_localStorageGet) -- Read a value from offchain local storage
- [`offchain_localStorageClear`](https://www.dwellir.com/docs/bittensor/offchain_localStorageClear) -- Remove a key from offchain local storage

---

## payment_queryFeeDetails - Bittensor RPC Method

# payment_queryFeeDetails - Bittensor RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Bittensor. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`payment_queryFeeDetails` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Bittensor
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/bittensor/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Bittensor RPC Method

# payment_queryInfo - Bittensor RPC Method

Estimates the fee for an encoded extrinsic on Bittensor. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`payment_queryInfo` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Bittensor
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/bittensor/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Bittensor RPC Method

# rpc_methods - Bittensor RPC Method

Returns a list of all RPC methods exposed by the Bittensor node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`rpc_methods` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Bittensor node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Bittensor endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Bittensor endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bittensor/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Bittensor RPC Method

# state_call - Bittensor RPC Method

Calls a runtime API function on Bittensor and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`state_call` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/bittensor/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) -- Get the node version for compatibility checking

---

## state_callAt - Bittensor RPC Method

# state_callAt - Bittensor RPC Method

Executes a runtime API function with SCALE-encoded parameters at a specific block hash. This is a variant of `state_call` that requires an explicit block hash, making it useful for historical queries. You can invoke any runtime API function exposed by the Bittensor runtime, such as `Metadata_metadata`, `AccountNonceApi_account_nonce`, or `TransactionPaymentApi_query_info`.

## Code Examples

## Request Parameters

- `method` (`string, required`): Runtime API function name (e.g. `"Metadata_metadata"`, `"AccountNonceApi_account_nonce"`).
- `data` (`string, required`): Hex-encoded SCALE-encoded call parameters. Use `"0x"` for functions that take no arguments.
- `blockHash` (`string, required`): Hex-encoded block hash to execute the call against.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_callAt",
  "params": [
    "<method>",
    "<data>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded SCALE-encoded return value. Must be decoded according to the runtime API's return type.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Historical metadata** -- Retrieve the runtime metadata as it existed at a past block to correctly decode storage and extrinsics from that era.
- **Fee estimation at past blocks** -- Call `TransactionPaymentApi_query_info` at historical blocks to analyze fee trends over time.
- **Cross-version analysis** -- Compare runtime API outputs across different blocks to track how Bittensor subnet parameters or staking rules evolved.

## Notes

- The `data` parameter must be SCALE-encoded. Use a library such as `@polkadot/types` or `parity-scale-codec` to encode input and decode output.
- Requires an archive node for historical block hashes. Non-archive nodes only retain recent state.
- This method is equivalent to `state_call` with an explicit block hash parameter.

## Related Methods

- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Runtime API call at the latest or a specified block
- [`archive_v1_call`](https://www.dwellir.com/docs/bittensor/archive_v1_call) -- Runtime call via the new JSON-RPC v2 archive API
- [`chainHead_v1_call`](https://www.dwellir.com/docs/bittensor/chainHead_v1_call) -- Runtime call within a follow subscription
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Shortcut for fetching runtime metadata

---

## state_getChildReadProof - Bittensor RPC Method

# state_getChildReadProof - Bittensor RPC Method

Returns a Merkle proof for one or more keys in a child storage trie at a given block. The proof can be used to verify the values of those keys without trusting the RPC provider -- the verifier only needs the state root from a trusted block header. This is the child-trie equivalent of `state_getReadProof`.

## Code Examples

## Request Parameters

- `childStorageKey` (`string, required`): Hex-encoded key identifying the child trie root.
- `keys` (`array, required`): Array of hex-encoded storage keys within the child trie to prove.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getChildReadProof",
  "params": [
    "<childStorageKey>",
    "<keys>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `at` (`string, required`): Block hash at which the proof was generated.
- `proof` (`array, required`): Array of hex-encoded trie nodes forming the Merkle proof.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "at": "<value>",
    "proof": []
  }
}
```

## Use Cases

- **Trust-minimized verification** -- Verify child storage values off-chain using only the state root from a trusted block header, without trusting the RPC provider.
- **Bridge proofs** -- Generate proofs for cross-chain bridges that need to verify Bittensor child storage state on another chain.
- **Light client support** -- Provide state proofs to light clients that do not store the full state trie.

## Notes

- Child trie usage is runtime-specific. Not all Bittensor pallets use child storage, so this method may return empty proofs for many queries.
- Replace the example parameters with actual child storage keys from the runtime you are querying.
- Requires an archive node for historical block hashes.

## Related Methods

- [`state_getReadProof`](https://www.dwellir.com/docs/bittensor/state_getReadProof) -- Generate Merkle proofs for main-trie storage keys
- [`childstate_getStorage`](https://www.dwellir.com/docs/bittensor/childstate_getStorage) -- Read child storage values (without proofs)
- [`childstate_getStorageEntries`](https://www.dwellir.com/docs/bittensor/childstate_getStorageEntries) -- Batch read child storage values
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read main-trie storage values

---

## state_getKeys - Bittensor RPC Method

# state_getKeys - Bittensor RPC Method

Returns all storage keys matching a given prefix. This method loads all matching keys into memory at once, which can be problematic for large storage maps. It is deprecated in favor of `state_getKeysPaged`, which supports cursor-based pagination and is safer for production use.

> **Deprecated:** Use [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) instead. This method may cause memory issues or timeouts on large storage maps.

## Code Examples

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix. Use the pallet's key prefix to list all keys in a storage map.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of all hex-encoded storage keys matching the prefix.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Small storage maps** -- Enumerate all keys in a storage map that you know to be small (e.g. a map with fewer than 1000 entries).
- **Quick exploration** -- Inspect which keys exist under a prefix during development or debugging.

## Notes

- This method returns all matching keys in a single response. For large maps (like `System.Account` on Bittensor), this can cause memory exhaustion or timeouts.
- Always prefer `state_getKeysPaged` for production code. It returns keys in pages and handles large maps safely.
- Requires an archive node for historical block hashes.

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Paginated key enumeration (recommended replacement)
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read the value for a specific key
- [`state_getPairs`](https://www.dwellir.com/docs/bittensor/state_getPairs) -- Get key-value pairs for a prefix (also deprecated)
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getKeysPaged - Bittensor RPC Method

# state_getKeysPaged - Bittensor RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Bittensor. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`state_getKeysPaged` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Bittensor
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getKeysPagedAt - JSON-RPC Method

# state_getKeysPagedAt - JSON-RPC Method

## Description

Enumerate storage keys for a prefix. Use for pagination when exploring large maps, then query values with state\_getStorage.

Returns storage keys with a given prefix, paginated, at a specific block hash.

## Code Examples

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage prefix to enumerate.
- `count` (`number, required`): Maximum number of keys to return in this page.
- `startKey` (`string | null, optional`): Optional cursor key from the previous page.
- `blockHash` (`string, required`): Hex-encoded block hash to read the state at.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPagedAt",
  "params": [
    "0x3a636f6465",
    10,
    null,
    "0x1e8a700fa840157d8d5617eac90ecd3b795d6469ddb8a9ec7dd2d051d806e85d"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array<string>, required`): Hex-encoded storage keys matching the prefix at the requested block hash.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x3a636f6465"
  ]
}
```

---

## state_getMetadata - Bittensor RPC Method

# state_getMetadata - Bittensor RPC Method

Returns the runtime metadata for Bittensor as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`state_getMetadata` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Bittensor
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Bittensor:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Bittensor:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) - Call runtime APIs described in metadata

---

## state_getPairs - Bittensor RPC Method

# state_getPairs - Bittensor RPC Method

Returns all storage key-value pairs matching a given prefix. Each entry in the result contains both the full storage key and its SCALE-encoded value. Like `state_getKeys`, this method loads all matching pairs into memory at once and can be problematic for large storage maps.

> **Note:** For large storage maps, consider using `state_getKeysPaged` to enumerate keys and then `state_getStorage` or `state_queryStorageAt` to fetch values in batches.

## Code Examples

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getPairs",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of `[key, value]` tuples where both are hex-encoded strings. Values are SCALE-encoded.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Small map export** -- Dump all entries from a storage map that is known to be small for analysis or migration.
- **Development and debugging** -- Quickly inspect the contents of a storage prefix during development.
- **State snapshots** -- Export a specific subset of on-chain state for offline analysis of Bittensor subnet data, staking maps, or other pallet storage.

## Notes

- Returns all matching pairs in a single response. For large maps this can cause memory exhaustion or timeouts.
- Values are SCALE-encoded. Decode them using the type information from runtime metadata.
- For production use with large maps, prefer paginated approaches: enumerate keys with `state_getKeysPaged`, then batch-fetch values with `state_queryStorageAt`.
- Requires an archive node for historical block hashes.

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Paginated key enumeration (safer for large maps)
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read a single storage value by key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- Batch-read multiple storage values at a block
- [`state_getKeys`](https://www.dwellir.com/docs/bittensor/state_getKeys) -- Get keys only (without values), also deprecated for large maps

---

## state_getReadProof - Bittensor RPC Method

# state_getReadProof - Bittensor RPC Method

Returns a Merkle proof for one or more storage keys at a given block. The proof consists of trie nodes that, together with the state root from a trusted block header, allow a verifier to confirm the values of the specified keys without trusting the RPC provider. This is essential for light clients, cross-chain bridges, and trust-minimized applications.

## Code Examples

## Request Parameters

- `keys` (`array, required`): Array of hex-encoded storage keys to generate proofs for.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getReadProof",
  "params": [
    "<keys>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `at` (`string, required`): Block hash at which the proof was generated.
- `proof` (`array, required`): Array of hex-encoded trie nodes forming the Merkle proof.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "at": "<value>",
    "proof": []
  }
}
```

## Use Cases

- **Trust-minimized verification** -- Verify storage values off-chain using only the state root from a trusted (finalized) block header.
- **Cross-chain bridges** -- Generate proofs that another chain can verify to confirm Bittensor on-chain state (e.g. account balances, subnet parameters).
- **Light clients** -- Provide state proofs to light clients that verify on-chain data without storing the full state trie.
- **Audit and compliance** -- Prove that specific on-chain values existed at a given block without requiring the verifier to run a full node.

## Notes

- The proof is generated against the state trie at the specified block. The verifier needs the `stateRoot` from that block's header.
- Proof verification can be performed using the `@polkadot/trie-hash` or `sp-trie` libraries.
- Requires an archive node for proofs at historical block hashes.

## Related Methods

- [`state_getChildReadProof`](https://www.dwellir.com/docs/bittensor/state_getChildReadProof) -- Generate proofs for child storage keys
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read storage values (without proofs)
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) -- Get the block header containing the state root
- [`state_getStorageAt`](https://www.dwellir.com/docs/bittensor/state_getStorageAt) -- Read storage at a specific block

---

## state_getRuntimeVersion - Bittensor RPC Method

# state_getRuntimeVersion - Bittensor RPC Method

Returns the runtime version information for Bittensor, including the spec name, spec version, implementation version, and supported API versions.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`state_getRuntimeVersion` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Bittensor
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Bittensor in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Bittensor RPC Method

# state_getStorage - Bittensor RPC Method

Returns the SCALE-encoded storage value for a given key on Bittensor. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`state_getStorage` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Bittensor
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Call runtime APIs for computed state that is not directly in storage
- [`state_subscribeStorage`](https://www.dwellir.com/docs/bittensor/state_subscribeStorage) -- Subscribe to storage changes in real time via WebSocket

---

## state_getStorageAt - Bittensor RPC Method

# state_getStorageAt - Bittensor RPC Method

Returns the SCALE-encoded storage value for a given key at a specific block hash. This is equivalent to `state_getStorage` with an explicit block hash parameter. Use it to read historical on-chain state at any past block on Bittensor, enabling time-travel queries for analytics, auditing, and debugging.

## Code Examples

## Request Parameters

- `key` (`string, required`): Hex-encoded storage key to read.
- `blockHash` (`string, required`): Hex-encoded block hash to read the storage at.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorageAt",
  "params": [
    "<key>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string` or `null, required`): Hex-encoded SCALE-encoded value, or `null` if the key does not exist at the given block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Historical balance queries** -- Read account balances, staking positions, or subnet parameters as they existed at a specific block.
- **Analytics and reporting** -- Build time-series data by reading the same storage key across a range of block hashes.
- **Debugging** -- Verify what on-chain state looked like at the block where an issue occurred.
- **Audit trails** -- Prove that a specific value existed on-chain at a given point in time.

## Notes

- Requires an archive node. Non-archive nodes only keep recent state (typically the last 256 blocks).
- The returned value is SCALE-encoded. Decode it using the type information from the runtime metadata at the same block.
- The example above uses the well-known `:code` key (`0x3a636f6465`) at a real Bittensor block hash. Replace it with the storage key you actually want to inspect.
- To determine the correct storage key for pallet state, use `state_getMetadata` and the Substrate storage key hashing scheme.

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read storage at the latest block (or optionally at a given hash)
- [`state_getStorageHash`](https://www.dwellir.com/docs/bittensor/state_getStorageHash) -- Get the hash of a storage value instead of the full value
- [`state_getStorageSize`](https://www.dwellir.com/docs/bittensor/state_getStorageSize) -- Get the byte size of a storage value
- [`state_queryStorage`](https://www.dwellir.com/docs/bittensor/state_queryStorage) -- Query storage changes across a range of blocks
- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Enumerate storage keys to discover what to query

---

## state_getStorageHash - Bittensor RPC Method

# state_getStorageHash - Bittensor RPC Method

Returns the hash (blake2b-256) of the storage value for a given key at the best block (or at a specific block hash if provided). This is a lightweight alternative to `state_getStorage` when you only need to detect whether a value has changed, without downloading the full value.

## Code Examples

## Request Parameters

- `key` (`string, required`): Hex-encoded storage key.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorageHash",
  "params": [
    "<key>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string` or `null, required`): Hex-encoded blake2b-256 hash of the storage value, or `null` if the key does not exist.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Change detection** -- Compare storage hashes across blocks to determine whether a value has changed without downloading the full (potentially large) value.
- **Caching optimization** -- Cache storage values locally and use the hash to determine if the cache is stale, avoiding unnecessary bandwidth for large values like the Wasm runtime blob.
- **Integrity verification** -- Confirm that a locally stored value matches the on-chain value by comparing hashes.

## Notes

- The hash is computed over the raw SCALE-encoded storage value.
- Returns `null` for non-existent keys, which is distinct from a key that exists with an empty value.
- Requires an archive node for historical block hashes.

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read the full storage value
- [`state_getStorageAt`](https://www.dwellir.com/docs/bittensor/state_getStorageAt) -- Read storage at a specific block hash
- [`state_getStorageSize`](https://www.dwellir.com/docs/bittensor/state_getStorageSize) -- Get the byte size of a storage value
- [`state_queryStorage`](https://www.dwellir.com/docs/bittensor/state_queryStorage) -- Track storage changes over a block range

---

## state_getStorageHashAt - JSON-RPC Method

# state_getStorageHashAt - JSON-RPC Method

## Description

Read SCALE‑encoded storage for a key (optionally at a specific block). Use to fetch on‑chain state deterministically and to implement historical reads.

Returns the storage hash for a key at the given block hash.

## Code Examples

## Request Parameters

- `key` (`string, required`): Hex-encoded storage key to hash.
- `blockHash` (`string, required`): Hex-encoded block hash to read the storage at.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorageHashAt",
  "params": [
    "0x3a636f6465",
    "0x1e8a700fa840157d8d5617eac90ecd3b795d6469ddb8a9ec7dd2d051d806e85d"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string | null, required`): Hex-encoded hash of the storage value at the requested block, or `null` when the key is absent.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x84aea08073c027fa3c5ecf0079b6beec969f8afc5558329b18616949ceb257af"
}
```

---

## state_getStorageSize - Bittensor RPC Method

# state_getStorageSize - Bittensor RPC Method

Returns the size in bytes of the SCALE-encoded storage value for a given key at the best block (or at a specified block hash). This is useful for checking whether a key exists and estimating the bandwidth needed to fetch its full value without actually downloading it.

ze in bytes of the storage value, or `null` if the key does not exist. |

## Code Examples

## Request Parameters

- `key` (`string, required`): Hex-encoded storage key.
- `blockHash` (`string, optional`): Hex-encoded block hash. Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorageSize",
  "params": [
    "<key>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`number` or `null, required`): Size in bytes of the storage value, or `null` if the key does not exist.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Use Cases

- **Existence check** -- Determine if a storage key exists without fetching the value (returns `null` for non-existent keys).
- **Bandwidth estimation** -- Estimate how much data will be transferred when reading a storage value, useful for planning batch reads.
- **Runtime code size** -- Check the size of the Wasm runtime blob stored under `:code` without downloading it.
- **Storage monitoring** -- Track the size of specific storage entries over time to monitor chain growth.

## Notes

- Returns the size of the raw SCALE-encoded value, not the decoded value.
- Returns `null` for non-existent keys rather than 0.
- Requires an archive node for historical block hashes.

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read the full storage value
- [`state_getStorageHash`](https://www.dwellir.com/docs/bittensor/state_getStorageHash) -- Get the hash of a storage value
- [`state_getStorageAt`](https://www.dwellir.com/docs/bittensor/state_getStorageAt) -- Read storage at a specific block hash
- [`childstate_getStorageSize`](https://www.dwellir.com/docs/bittensor/childstate_getStorageSize) -- Get size of child trie storage values

---

## state_getStorageSizeAt - JSON-RPC Method

# state_getStorageSizeAt - JSON-RPC Method

## Description

Read SCALE‑encoded storage for a key (optionally at a specific block). Use to fetch on‑chain state deterministically and to implement historical reads.

Returns the size (in bytes) of the storage value for the key at the given block.

## Code Examples

## Request Parameters

- `key` (`string, required`): Hex-encoded storage key to measure.
- `blockHash` (`string, required`): Hex-encoded block hash to read the storage at.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorageSizeAt",
  "params": [
    "0x3a636f6465",
    "0x1e8a700fa840157d8d5617eac90ecd3b795d6469ddb8a9ec7dd2d051d806e85d"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`number, required`): Byte length of the stored SCALE value at the requested block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 1659177
}
```

---

## state_queryStorage - Bittensor RPC Method

# state_queryStorage - Bittensor RPC Method

Returns the storage changes for the specified keys over a range of blocks. For each block in the range where at least one of the queried keys changed, the method returns the block hash and the new values. This is useful for tracking how specific storage entries evolved over time without having to query each block individually.

## Code Examples

## Request Parameters

- `keys` (`array, required`): Array of hex-encoded storage keys to track.
- `fromBlock` (`string, required`): Hex-encoded hash of the starting block (inclusive).
- `toBlock` (`string, optional`): Hex-encoded hash of the ending block (inclusive). Defaults to the best block if omitted.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorage",
  "params": [
    "<keys>",
    "<fromBlock>",
    "<toBlock>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of change sets. Each entry has `block` (block hash) and `changes` (array of `[key, value]` pairs).

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Balance history** -- Track how an account balance changed over a range of blocks.
- **Parameter tracking** -- Monitor changes to Bittensor subnet parameters, staking rates, or other governance-controlled values over time.
- **Event-driven indexing** -- Detect which blocks contained changes to specific storage entries, then process only those blocks.
- **Debugging** -- Identify exactly when a storage value changed during incident investigation.

## Notes

- This method can be expensive for large block ranges. The node must replay each block in the range to detect changes. Consider using narrow ranges.
- For single-block queries, prefer `state_queryStorageAt` which is optimized for that case.
- Only blocks where at least one queried key changed are included in the result.
- Requires an archive node for historical block ranges.
- On Dwellir shared public Bittensor endpoints this range query is currently treated as unsafe. Expect `RPC call is unsafe to be called externally` unless you run it on infrastructure that exposes the method.

## Related Methods

- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- Query storage at a single block (more efficient for point-in-time queries)
- [`state_subscribeStorage`](https://www.dwellir.com/docs/bittensor/state_subscribeStorage) -- Subscribe to live storage changes via WebSocket
- [`state_getStorageAt`](https://www.dwellir.com/docs/bittensor/state_getStorageAt) -- Read a single storage value at a specific block
- [`archive_v1_storageDiff`](https://www.dwellir.com/docs/bittensor/archive_v1_storageDiff) -- v2 API for streaming storage changes between blocks

---

## state_queryStorageAt - Bittensor RPC Method

# state_queryStorageAt - Bittensor RPC Method

Queries multiple storage keys at a specific block on Bittensor, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`state_queryStorageAt` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Bittensor
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/bittensor/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/bittensor/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bittensor/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## state_subscribeRuntimeVersion - JSON-RPC M...

# state_subscribeRuntimeVersion - JSON-RPC M...

Subscribes to runtime version updates over a WebSocket connection. Use it to detect Bittensor runtime upgrades so your indexers, signers, and type registries can refresh before decoding new blocks or extrinsics.

The initial JSON-RPC response returns a subscription ID. Runtime version objects are delivered afterward as WebSocket notifications on that subscription.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_subscribeRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`string, required`): Subscription ID returned by the node. Runtime version notifications are delivered afterward on this subscription.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_subscribeRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

### JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const api = await ApiPromise.create({
  provider: new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
});

const unsub = await api.rpc.state.subscribeRuntimeVersion((version) => {
  console.log(`Runtime upgrade detected: specVersion=${version.specVersion}`);
  console.log(`Transaction version: ${version.transactionVersion}`);
});

// Later: unsub();
```

## Use Cases

- **Metadata refresh** -- Detect runtime upgrades and reload metadata before decoding new blocks or extrinsics.
- **Signer safety** -- Watch `transactionVersion` changes that can invalidate previously prepared unsigned transactions.
- **Operational alerting** -- Notify operators or dashboards when Bittensor upgrades on-chain logic.

## Notes

- The first notification typically arrives immediately with the current runtime version.
- Cancel the subscription with `state_unsubscribeRuntimeVersion` when you no longer need updates.
- This subscription is WebSocket-only.

## Related Methods

- [`state_unsubscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_unsubscribeRuntimeVersion) -- Cancel this subscription
- [`chain_subscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_subscribeRuntimeVersion) -- Equivalent runtime-version subscription via the chain namespace
- [`chain_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_getRuntimeVersion) -- One-shot runtime version query

---

## state_subscribeStorage - Bittensor RPC Method

# state_subscribeStorage - Bittensor RPC Method

Subscribes to storage changes for a set of keys via a WebSocket connection. Each time one or more of the specified keys change in a new block, a notification is emitted with the updated values. This enables real-time reactive applications that respond to on-chain state changes without polling.

The initial JSON-RPC response returns a subscription ID. Storage-change payloads are delivered afterward as WebSocket notifications for that subscription.

## Request Parameters

- `keys` (`array, required`): Array of hex-encoded storage keys to watch.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_subscribeStorage",
    "params": [
      ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"]
    ],
    "id": 1
  }'
```

## Response Fields

- `block` (`string, required`): Block hash where the changes occurred.
- `changes` (`array, required`): Array of `[key, value]` pairs for keys that changed. Values are hex-encoded SCALE or `null` if deleted.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_subscribeStorage",
    "params": [
      ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"]
    ],
    "id": 1
  }'
```

### JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const api = await ApiPromise.create({
  provider: new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
});

const unsub = await api.rpc.state.subscribeStorage(
  ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'],
  (changes) => {
    console.log('Storage changed:', changes.toHuman());
  }
);

// Later: unsub();
```

## Use Cases

- **Live balance tracking** -- Watch account balance changes in real time for wallet UIs or notification systems.
- **Parameter monitoring** -- Get instant notifications when Bittensor subnet parameters, staking configurations, or governance values change.
- **Event-driven processing** -- Trigger downstream actions (alerts, database updates, API calls) when specific on-chain state changes.

## Notes

- Cancel the subscription with `state_unsubscribeStorage` when no longer needed to free server resources.
- The initial notification includes the current values of all watched keys.
- This is a WebSocket-only method; not available over HTTP.

## Related Methods

- [`state_unsubscribeStorage`](https://www.dwellir.com/docs/bittensor/state_unsubscribeStorage) -- Cancel this subscription
- [`state_queryStorage`](https://www.dwellir.com/docs/bittensor/state_queryStorage) -- Query historical storage changes over a block range
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- Point-in-time storage query
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Subscribe to new block headers

---

## state_traceBlock - JSON-RPC Method

# state_traceBlock - JSON-RPC Method

Traces a block execution. Typically restricted; may require node flags.

> Public endpoints commonly reject this method as unsafe unless tracing is
> explicitly enabled on the node.

## Code Examples

## Request Parameters

- `block` (`string, required`): Hex-encoded block hash to replay.
- `targets` (`string, optional`): Comma-separated trace targets such as `state` or pallet-specific filters.
- `storageKeys` (`string, optional`): Optional storage keys to trace during block execution.
- `methods` (`string, optional`): Optional method filters used by tracing-enabled nodes.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_traceBlock",
  "params": [
    "<blockHash>",
    "state",
    "",
    ""
  ],
  "id": 1
}
```

## Response Fields

- `result` (`object, required`): Trace output emitted by tracing-enabled nodes. Public endpoints may reject this method as unsafe.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "blockTrace": [],
    "storageProofs": []
  }
}
```

## Error Responses

### Unsafe RPC Error

- Code: `4003`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 4003,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

---

## state_unsubscribeRuntimeVersion - Bittensor RPC Method

# state_unsubscribeRuntimeVersion - Bittensor RPC Method

Cancels a WebSocket subscription that was started with `state_subscribeRuntimeVersion`. After calling this method, no further runtime version notifications will be delivered for that subscription. Provide the subscription ID that was returned when the subscription was created.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `state_subscribeRuntimeVersion`.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_unsubscribeRuntimeVersion",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_unsubscribeRuntimeVersion",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Subscription cleanup** -- Cancel the runtime version subscription when your application no longer needs to track runtime upgrades.
- **Resource management** -- Free server-side resources in long-running WebSocket applications.
- **Subscription rotation** -- Stop an existing subscription before starting a new one after reconnection.

## Notes

- Always unsubscribe when done to prevent server-side resource leaks.
- The `chain_unsubscribeRuntimeVersion` method in the `chain` namespace serves the same purpose if the subscription was started with `chain_subscribeRuntimeVersion`.
- WebSocket-only; cannot be called over HTTP.

## Related Methods

- [`state_subscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_subscribeRuntimeVersion) -- Start the subscription this method cancels
- [`chain_subscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_subscribeRuntimeVersion) -- Subscribe via the chain namespace
- [`state_unsubscribeStorage`](https://www.dwellir.com/docs/bittensor/state_unsubscribeStorage) -- Cancel a storage subscription
- [`chain_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/chain_getRuntimeVersion) -- One-shot query for current runtime version

---

## state_unsubscribeStorage - Bittensor RPC Method

# state_unsubscribeStorage - Bittensor RPC Method

Cancels a WebSocket subscription that was started with `state_subscribeStorage`. After calling this method, no further storage change notifications will be delivered for that subscription. Provide the subscription ID that was returned when the subscription was created.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `state_subscribeStorage`.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_unsubscribeStorage",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if the subscription was successfully cancelled, `false` if the ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "state_unsubscribeStorage",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Subscription cleanup** -- Cancel storage change notifications when your application no longer needs real-time updates for those keys.
- **Resource management** -- Free server-side memory and bandwidth by removing unused subscriptions.
- **Key set changes** -- Unsubscribe from the current key set and create a new subscription with a different set of keys to watch.

## Notes

- Always unsubscribe when done to prevent server-side resource leaks, especially in long-running applications.
- If the WebSocket connection drops, subscriptions are automatically cleaned up, but explicit unsubscription is still best practice.
- WebSocket-only; cannot be called over HTTP.

## Related Methods

- [`state_subscribeStorage`](https://www.dwellir.com/docs/bittensor/state_subscribeStorage) -- Start the subscription this method cancels
- [`state_unsubscribeRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_unsubscribeRuntimeVersion) -- Cancel a runtime version subscription
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bittensor/state_queryStorageAt) -- One-shot storage query as an alternative to subscriptions

---

## subnetInfo_getAllDynamicInfo - JSON-RPC Me...

# subnetInfo_getAllDynamicInfo - JSON-RPC Me...

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns dynamic info for all subnets (SCALE-encoded bytes).

## Code Examples

## Request Parameters

- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getAllDynamicInfo",
  "params": [
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded dynamic subnet information for every subnet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    5,
    2,
    1,
    0
  ]
}
```

---

## subnetInfo_getAllMechagraphs - JSON-RPC Me...

# subnetInfo_getAllMechagraphs - JSON-RPC Me...

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns mechagraphs for all subnets.

## Code Examples

## Request Parameters

- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getAllMechagraphs",
  "params": [
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded mechagraph payloads for all subnets.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    0,
    1,
    2,
    3
  ]
}
```

---

## subnetInfo_getAllMetagraphs - Bittensor RPC Method

# subnetInfo_getAllMetagraphs - Bittensor RPC Method

## Overview

The `subnetInfo_getAllMetagraphs` method returns the SCALE-encoded metagraphs for every active subnet on the Bittensor network in a single RPC call. This is the bulk equivalent of calling `subnetInfo_getMetagraph` for each netuid individually.

Each metagraph contains the complete topology of a subnet: all registered neurons, their stakes, trust scores, incentive values, weight matrices, emission distributions, and axon endpoints. By fetching all metagraphs at once, you can efficiently perform cross-subnet analysis and build network-wide monitoring dashboards.

> **Note:** This method returns a large payload since it includes metagraph data for every active subnet. Expect response sizes in the range of several megabytes for networks with many subnets. Consider using `subnetInfo_getMetagraph` for targeted single-subnet queries when you only need specific data.

## SCALE Decoding

The response decodes to `Vec<MetagraphInfo>`, where each `MetagraphInfo` contains the fields above. Due to the size of this response, decoding can be computationally intensive.

**Using `@polkadot/api`:** Register all Bittensor types including `MetagraphInfo` and `AxonInfo` before calling. The decoded result is an array that can be iterated. Each element has the same structure as the single `subnetInfo_getMetagraph` response.

**Using `bittensor` Python SDK:** There is no single SDK call that returns all metagraphs at once. Instead, iterate over subnet netuids: `for netuid in sub.get_all_subnet_netuids(): meta = sub.metagraph(netuid=netuid)`. For the raw RPC approach, decode `Vec<MetagraphInfo>` using the Bittensor type registry.

**Performance notes:**

- The total payload can exceed 10 MB for networks with 30+ active subnets
- Decoding time scales linearly with the number of subnets and neurons
- Consider processing the response in a background thread to avoid blocking your main application
- Cache the result and refresh at a cadence appropriate for your use case (once per tempo or less frequently)

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `at` (`DATA, optional`): Optional block hash used as the state reference for the query.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getAllMetagraphs",
    "params": [null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded metagraph payload for all subnets.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0123456789abcdef"
}
```

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getAllMetagraphs',
    'params': [None],
    'id': 1
}

response = requests.post(url, json=payload, timeout=60)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'All metagraphs SCALE data size: {len(scale_bytes)} bytes')
    print(f'Approximate size: {len(scale_bytes) // 2 / 1024:.1f} KB')
else:
    print('No metagraphs returned')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# for netuid in sub.get_all_subnet_netuids():
#     meta = sub.metagraph(netuid=netuid)
#     print(f"Subnet {netuid}: {meta.n} neurons, emissions: {meta.E.sum():.4f}")
```

### Full Python cross-subnet analysis

```python
import bittensor as bt
import numpy as np

sub = bt.subtensor(network='finney')
netuids = sub.get_all_subnet_netuids()

print(f"{'Netuid':>6} {'Neurons':>8} {'Validators':>11} {'Total Stake':>15} {'Emissions':>12} {'Avg Trust':>10}")
print("-" * 66)

total_neurons = 0
total_stake = 0

for netuid in netuids:
    try:
        meta = sub.metagraph(netuid=netuid)
        n_validators = sum(meta.validator_permit)
        total_s = meta.S.sum()
        total_e = meta.E.sum()
        avg_trust = meta.T.mean()

        total_neurons += meta.n
        total_stake += total_s

        print(f"{netuid:>6} {meta.n:>8} {n_validators:>11} {total_s:>14,.2f} {total_e:>11,.4f} {avg_trust:>9,.4f}")
    except Exception as e:
        print(f"{netuid:>6} Error: {e}")

print("-" * 66)
print(f"Total neurons: {total_neurons}, Total stake: {total_stake:,.2f} TAO")

# Find hotkeys registered on multiple subnets
hotkey_subnets = {}
for netuid in netuids:
    meta = sub.metagraph(netuid=netuid)
    for uid in range(meta.n):
        hk = meta.hotkeys[uid]
        hotkey_subnets.setdefault(hk, []).append(netuid)

multi_subnet = {k: v for k, v in hotkey_subnets.items() if len(v) > 1}
print(f"\nHotkeys on multiple subnets: {len(multi_subnet)}")
for hk, nets in sorted(multi_subnet.items(), key=lambda x: len(x[1]), reverse=True)[:5]:
    print(f"  {hk[:18]}.. on subnets: {nets}")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const allMetagraphs = await api.rpc.subnetInfo.getAllMetagraphs();
console.log('Raw data size:', allMetagraphs.toHex().length, 'bytes');

// With Bittensor type definitions registered, iterate decoded metagraphs
// for (const meta of allMetagraphs) {
//   console.log(`Subnet ${meta.netuid}: ${meta.n} neurons`);
// }

await api.disconnect();
```

## Common Use Cases

- **Network-wide analytics** — Build dashboards that aggregate neuron counts, total stake, emission distributions, and health metrics across all subnets.
- **Cross-subnet comparisons** — Compare validator performance, miner incentive scores, and consensus quality between subnets.
- **Global monitoring** — Track network growth by monitoring how many neurons are registered across all subnets over time.
- **Emission analysis** — Visualize how TAO emissions are distributed across subnets and identify which subnets receive the most rewards.
- **Research** — Study the global network topology and how different subnet configurations affect incentive dynamics.
- **Multi-subnet operators** — Monitor all your neurons across subnets in a single query instead of making individual calls.

## Related Methods

- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get metagraph for a single subnet (lighter response)
- [`subnetInfo_getSelectiveMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSelectiveMetagraph) — Get filtered metagraph data for specific neuron UIDs
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get configuration info for all subnets
- [`subnetInfo_getAllDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllDynamicInfo) — Get dynamic info for all subnets
- [`subnetInfo_getAllMechagraphs`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllMechagraphs) — Get mechagraphs for all subnets

---

## subnetInfo_getColdkeyAutoStakeHotkey - Bittensor RPC Method

# subnetInfo_getColdkeyAutoStakeHotkey - Bittensor RPC Method

## Overview

The `subnetInfo_getColdkeyAutoStakeHotkey` method returns the hotkey that has been configured for auto-staking on behalf of a given coldkey within a Bittensor subnet. Auto-staking is a convenience feature that automatically delegates newly received TAO (such as emissions or transfers) to a designated hotkey, removing the need for manual re-staking.

When a coldkey sets an auto-stake hotkey, any TAO that arrives in the coldkey's account is automatically staked to the specified hotkey. This is particularly useful for validators and miners who want to compound their emissions without manual intervention.

## How Auto-Staking Works

Auto-staking in Bittensor provides automated compounding of rewards:

1. **Configuration:** The coldkey owner sets an auto-stake target hotkey using a Bittensor extrinsic (transaction)
2. **Trigger:** When the coldkey receives TAO (from emissions, transfers, or unstaking), the auto-stake mechanism detects the incoming funds
3. **Execution:** The received TAO is automatically staked to the configured hotkey
4. **Benefit:** This creates a compounding effect -- emissions earn more stake, which earns more emissions

Auto-staking can be subnet-specific, allowing different hotkeys for different subnets. This is useful for operators who run validators on multiple subnets with different hotkeys.

## SCALE Decoding

Decode the response as `Option<AccountId32>`.

- `[]` or `[0]` indicates `None` on shared endpoints that serialize SCALE bytes into JSON arrays.
- A populated response contains the SCALE bytes for `Some(AccountId32)`.
- Convert the decoded `AccountId32` back to SS58 with the chain's `ss58Format` when you need a human-readable hotkey.

## Code Examples

### Using SubstrateExamples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getColdkeyAutoStakeHotkey",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - Encoded hotkey bytes, where the method returns auto-staked hotkey info for a coldkey/netuid pair.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0a1b2c3d4e5f"
}
```

### Query with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getColdkeyAutoStakeHotkey',
    'params': ['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', 1, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

scale_bytes = result.get('result', [])
if scale_bytes not in ([], [0]):
    print(f'SCALE bytes for auto-stake hotkey: {scale_bytes}')
else:
    print('No auto-stake hotkey configured')

# With bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# hotkey = sub.get_coldkey_auto_stake_hotkey(coldkey_ss58, netuid=1)
# print(f"Auto-stake target: {hotkey}")
```

### Full Python auto-stake verification

```python
import bittensor as bt

sub = bt.subtensor(network='finney')

# Check auto-stake configuration for a coldkey
coldkey_ss58 = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'

# Check across multiple subnets
netuids = sub.get_all_subnet_netuids()
print(f"Checking auto-stake for {coldkey_ss58[:18]}...\n")

auto_stake_found = False
for netuid in netuids:
    try:
        hotkey = sub.get_coldkey_auto_stake_hotkey(coldkey_ss58, netuid=netuid)
        if hotkey:
            auto_stake_found = True
            # Verify the hotkey is still a valid delegate
            delegate = sub.get_delegate_by_hotkey(hotkey)
            status = "active delegate" if delegate else "not a delegate"
            print(f"Subnet {netuid:>3}: auto-stake -> {hotkey[:18]}.. ({status})")
    except Exception as e:
        pass  # Method may not be supported for all subnets

if not auto_stake_found:
    print("No auto-stake configured on any subnet")

# Verify auto-stake is compounding correctly
# by checking stake changes over time
print("\n--- Compounding verification ---")
delegations = sub.get_delegated(coldkey_ss58)
for delegate_info, staked_amount in delegations:
    print(f"Delegate {delegate_info.hotkey_ss58[:18]}.. : "
          f"{staked_amount.tao:,.2f} TAO staked")
```

### Query with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const result = await api.rpc.subnetInfo.getColdkeyAutoStakeHotkey(
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  1,
  null,
);
if (!result.isEmpty) {
  console.log('Auto-stake hotkey:', result.toHuman());
} else {
  console.log('No auto-stake hotkey configured');
}

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getColdkeyAutoStakeHotkey",
    "params": ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1, null],
    "id": 1
  }'
```

## Common Use Cases

- **Staking automation** — Verify that auto-staking is correctly configured for a coldkey so emissions are automatically compounded.
- **Delegation management** — Check which hotkey is receiving auto-staked TAO for an account.
- **Validator operations** — Ensure your coldkey's auto-stake target points to the correct validator hotkey after key rotation or migration.
- **Account auditing** — Verify auto-stake configuration as part of security reviews or account management workflows.
- **Dashboard integration** — Display auto-stake configuration alongside other staking information in portfolio views.
- **Compounding verification** — Cross-reference auto-stake settings with actual delegation amounts to verify compounding is working as expected.
- **Multi-subnet operators** — Verify that subnet-specific auto-stake targets are correctly configured for each subnet you operate on.

## Related Methods

- [`delegateInfo_getDelegated`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegated) — Get all delegations for an account (verify auto-staked amounts)
- [`delegateInfo_getDelegate`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegate) — Get info for a specific delegate (verify target hotkey is valid)
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the metagraph for a subnet
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic subnet info (emission rates affect compounding)
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get info for all subnets

---

## subnetInfo_getDynamicInfo - Bittensor RPC Method

# subnetInfo_getDynamicInfo - Bittensor RPC Method

## Overview

The `subnetInfo_getDynamicInfo` method returns SCALE-encoded dynamic runtime information for a specific Bittensor subnet. While `subnetInfo_getSubnetsInfo` returns static configuration, this method returns real-time economic data that changes every tempo: emission rates, registration costs, alpha token pricing, and other values that reflect the current state of the subnet's economy.

This method is essential for understanding the economic dynamics of a subnet -- how much TAO it receives, what it costs to register, and how its internal token (alpha) is priced.

## SCALE Decoding

The response decodes to a single `SubnetDynamicInfo` struct using Bittensor's custom type registry.

**Using `@polkadot/api`:** Register the `SubnetDynamicInfo` type definition. Key types within the struct include `AccountId32`, `u16`, `u64`, `bool`, and `Option<SubnetIdentity>`. The `SubnetIdentity` struct typically contains `name` (`Vec<u8>`) and `description` (`Vec<u8>`) fields.

**Using `bittensor` Python SDK:** Use `sub.get_subnet_dynamic_info(netuid=N)` which returns a decoded object with all fields accessible as properties.

**Key decoding notes:**

- The `price` field represents the alpha-to-TAO exchange rate. The exact scaling factor depends on the runtime version
- `alpha_in` and `tao_in` define the AMM pool state. The constant product `k = alpha_in * tao_in` determines swap pricing
- `pending_emission` accumulates between tempos. After each tempo, pending emissions are distributed to neurons based on their scores
- `is_dynamic` indicates whether the subnet participates in the dynamic TAO system. Non-dynamic subnets have simpler emission mechanics
- `network_registered_at` is the genesis block for this subnet -- useful for calculating subnet age

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `netuid` (`INTEGER, required`): Numeric subnet identifier.
- `at` (`DATA, optional`): Optional block hash to query state at.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getDynamicInfo",
    "params": [1, null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded dynamic subnet info.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x9abcdeff"
}
```

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Fetch dynamic info for subnet 1
payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getDynamicInfo',
    'params': [1, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'Dynamic info SCALE data size: {len(scale_bytes)} bytes')
else:
    print('No dynamic info found for this subnet')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# dyn_info = sub.get_subnet_dynamic_info(netuid=1)
# print(f"Emission: {dyn_info.emission_value} RAO/block")
# print(f"Burn cost: {dyn_info.burn / 1e9:.4f} TAO")
# print(f"Alpha price: {dyn_info.price}")
```

### Full Python economic analysis

```python
import bittensor as bt

sub = bt.subtensor(network='finney')

# Analyze economics for a specific subnet
netuid = 1
dyn = sub.get_subnet_dynamic_info(netuid=netuid)
current_block = sub.block

print(f"=== Subnet {netuid} Economics ===")
print(f"Owner: {dyn.owner}")
print(f"Registered at block: {dyn.network_registered_at}")
print(f"Subnet age: {current_block - dyn.network_registered_at:,} blocks")
print(f"Tempo: {dyn.tempo} blocks (~{dyn.tempo * 12 / 60:.1f} minutes)")

# Emission analysis
daily_emission_tao = (dyn.emission_value / 1e9) * 7200
print(f"\nEmission: {dyn.emission_value / 1e9:.6f} TAO/block")
print(f"Daily emission: {daily_emission_tao:,.2f} TAO")
print(f"Pending emission: {dyn.pending_emission / 1e9:,.4f} TAO")
print(f"Pending alpha emission: {dyn.pending_alpha_emission / 1e9:,.4f} TAO")
print(f"Pending root emission: {dyn.pending_root_emission / 1e9:,.4f} TAO")

# Registration costs
print(f"\nRegistration burn cost: {dyn.burn / 1e9:,.4f} TAO")
print(f"Registration difficulty: {dyn.difficulty:,}")

# Dynamic TAO / Alpha token economics
if dyn.is_dynamic:
    print(f"\nDynamic TAO: Enabled")
    print(f"Alpha in pool: {dyn.alpha_in / 1e9:,.4f}")
    print(f"TAO in pool: {dyn.tao_in / 1e9:,.4f}")
    print(f"Alpha price: {dyn.price}")
    print(f"Pool constant k: {dyn.k}")
    print(f"Alpha distributed: {dyn.alpha_out / 1e9:,.4f}")
else:
    print(f"\nDynamic TAO: Disabled (traditional emission model)")

# Subnet identity
if dyn.subnet_identity:
    print(f"\nSubnet name: {dyn.subnet_identity.name}")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const dynamicInfo = await api.rpc.subnetInfo.getDynamicInfo(1);
console.log('Raw data:', dynamicInfo.toHex().slice(0, 80), '...');

// With Bittensor types registered:
// console.log('Emission:', dynamicInfo.emission_value.toString());
// console.log('Burn:', dynamicInfo.burn.toString());
// console.log('Dynamic TAO:', dynamicInfo.is_dynamic.toString());
// console.log('Alpha price:', dynamicInfo.price.toString());

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getDynamicInfo",
    "params": [1, null],
    "id": 1
  }'
```

zero | Handle both dynamic and non-dynamic subnet modes |
\| Invalid block hash | Returns JSON-RPC error | Verify block hash exists on chain |
\| Node not synced | May return stale economic data | Check `system_health` for sync status |
\| Rate limit exceeded | HTTP 429 | Cache results; refresh once per tempo at most |

## Common Use Cases

- **Subnet economics** — Analyze emission rates, alpha token pricing, and registration costs to understand the economic health of a subnet.
- **Emission tracking** — Monitor how emissions change over time for a subnet, including pending emissions not yet distributed.
- **Registration planning** — Check the current burn cost and difficulty before registering a neuron on a subnet.
- **Alpha token pricing** — Track the alpha-to-TAO exchange rate and AMM pool state for dynamic TAO subnets. Use `alpha_in` and `tao_in` to calculate slippage for planned swaps.
- **Investment analysis** — Evaluate subnet economics (emission share, token dynamics) for staking and delegation decisions.
- **Dashboard widgets** — Display real-time subnet economic indicators in monitoring tools.
- **Subnet age analysis** — Use `network_registered_at` to calculate subnet maturity and correlate with performance metrics.

## Related Methods

- [`subnetInfo_getAllDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllDynamicInfo) — Get dynamic info for all subnets
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get static configuration for all subnets
- [`subnetInfo_getLockCost`](https://www.dwellir.com/docs/bittensor/subnetInfo_getLockCost) — Get the TAO lock cost for subnet registration
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the metagraph topology for a subnet
- [`swap_currentAlphaPrice`](https://www.dwellir.com/docs/bittensor/swap_currentAlphaPrice) — Get the current alpha token price for swap operations

---

## subnetInfo_getLockCost - Bittensor RPC Method

# subnetInfo_getLockCost - Bittensor RPC Method

## Overview

The `subnetInfo_getLockCost` method returns the current TAO lock cost required to register a new subnet on the Bittensor network. Creating a subnet requires locking a significant amount of TAO, and this cost fluctuates dynamically based on network demand -- when more subnets are being created, the lock cost increases; when subnet registrations slow down, it decreases.

The lock cost acts as an economic barrier to prevent spam subnet creation and ensure that subnet operators have meaningful skin in the game. The locked TAO is returned when the subnet is dissolved, but is at risk if the subnet is pruned for underperformance.

This method returns a single numeric value (in RAO, where 1 TAO = 10^9 RAO) and is not SCALE-encoded like other subnet methods.

## How the Lock Cost Works

The lock cost is determined by a dynamic pricing mechanism:

- **Base cost:** There is a minimum lock cost floor that prevents subnets from being created for trivial amounts
- **Demand scaling:** As more subnets are registered, the cost increases exponentially. Each new subnet registration roughly doubles the cost for the next
- **Decay:** When no new subnets are registered, the cost gradually decays back toward the floor over time
- **Maximum subnets:** The network has a hard cap on the number of concurrent subnets. When this limit is reached, new subnets can only be created by replacing (pruning) the lowest-performing existing subnet
- **Lock vs. burn:** The locked TAO is not burned -- it remains locked to the subnet and is returned if the subnet is dissolved by its owner. However, if the subnet is pruned by the network for underperformance, the lock may be lost

This creates a competitive market for subnet slots: operators must evaluate whether the lock cost is justified by the expected emissions their subnet will earn.

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `at` (`DATA, optional`): Optional block hash used for the request.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getLockCost",
    "params": [null],
    "id": 1
  }'
```

## Response Fields

- `result` (`INTEGER, required`): Lock cost in the chain unit for subnet operations.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 100
}
```

### Query with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getLockCost',
    'params': [None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result') is not None:
    lock_cost_rao = int(result['result'])
    lock_cost_tao = lock_cost_rao / 1e9
    print(f'Current subnet lock cost: {lock_cost_tao:.4f} TAO')
    print(f'Lock cost in RAO: {lock_cost_rao:,}')
else:
    print('Could not fetch lock cost')

# With bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# lock_cost = sub.get_subnet_burn_cost()
# print(f"Lock cost: {lock_cost / 1e9:.4f} TAO")
```

### Full Python cost analysis

```python
import bittensor as bt
import requests
import json

sub = bt.subtensor(network='finney')

# Get current lock cost
lock_cost_rao = sub.get_subnet_burn_cost()
lock_cost_tao = lock_cost_rao / 1e9

# Get current network state for context
subnets = sub.get_all_subnets_info()
active_subnets = [s for s in subnets if s is not None]
total_subnets = len(active_subnets)

print(f"=== Subnet Registration Cost Analysis ===")
print(f"Current lock cost: {lock_cost_tao:,.2f} TAO ({lock_cost_rao:,} RAO)")
print(f"Active subnets: {total_subnets}")

# Estimate ROI: compare lock cost against potential emission income
# Average daily emission per subnet
total_daily_emissions = sum(
    (s.emission_value / 1e9) * 7200 for s in active_subnets
)
avg_daily_per_subnet = total_daily_emissions / total_subnets

print(f"\nTotal daily emissions (all subnets): {total_daily_emissions:,.2f} TAO")
print(f"Average daily emission per subnet: {avg_daily_per_subnet:,.2f} TAO")
print(f"Days to recover lock cost (at avg emission): {lock_cost_tao / avg_daily_per_subnet:,.0f}")
print(f"Annualized ROI (at avg emission): {(avg_daily_per_subnet * 365 / lock_cost_tao) * 100:,.1f}%")

# Track lock cost history by querying at past blocks
url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
current_block = sub.block
check_blocks = [current_block - 7200, current_block - 7200 * 7]  # 1 day ago, 1 week ago

for blocks_ago_block in check_blocks:
    try:
        block_hash = sub.get_block_hash(blocks_ago_block)
        payload = {
            'jsonrpc': '2.0',
            'method': 'subnetInfo_getLockCost',
            'params': [block_hash],
            'id': 1
        }
        resp = requests.post(url, json=payload)
        past_cost = int(resp.json()['result']) / 1e9
        change = ((lock_cost_tao - past_cost) / past_cost) * 100
        print(f"Lock cost at block {blocks_ago_block}: {past_cost:,.2f} TAO ({change:+.1f}% change)")
    except Exception as e:
        print(f"Could not fetch historical cost: {e}")
```

### Query with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const lockCost = await api.rpc.subnetInfo.getLockCost();
const tao = Number(lockCost) / 1e9;
console.log(`Current subnet lock cost: ${tao.toFixed(4)} TAO`);

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getLockCost",
    "params": [null],
    "id": 1
  }'
```

zero or negative | Should not happen; indicates node issue | Retry with a different node or check node health |
\| Rate limit exceeded | HTTP 429 | Cache results; lock cost changes slowly (poll every few minutes) |

## Common Use Cases

- **Subnet creation planning** — Check the current lock cost before committing to register a new subnet. Time your registration when costs are lower.
- **Cost monitoring** — Track how the lock cost changes over time to understand network demand for new subnets.
- **Budget estimation** — Calculate the total TAO required for subnet operations (lock cost + registration burns for neurons + staking).
- **Economic analysis** — Study the relationship between lock cost dynamics and subnet creation/dissolution rates.
- **Alerting** — Set up alerts when the lock cost drops below a threshold, signaling a good time to register.
- **ROI modeling** — Compare the lock cost against expected subnet emissions to evaluate the investment case for creating a new subnet.
- **Competitive intelligence** — Monitor lock cost trends to anticipate when new subnets are likely to be created.

## Related Methods

- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic info including emission rates and registration costs for a subnet
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get configuration info for all subnets
- [`subnetInfo_getSubnetToPrune`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetToPrune) — Check which subnet is next in line for pruning
- [`subnetInfo_getSubnetInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetInfo) — Get info for a single subnet
- [`swap_currentAlphaPrice`](https://www.dwellir.com/docs/bittensor/swap_currentAlphaPrice) — Get the current alpha token price

---

## subnetInfo_getMechagraph - Bittensor RPC Method

# subnetInfo_getMechagraph - Bittensor RPC Method

## Overview

The `subnetInfo_getMechagraph` method returns the SCALE-encoded mechagraph for a specific subnet (`netuid`) and mechanism ID (`mecid`) on the Bittensor network. The mechagraph is a more granular view of subnet topology that captures mechanism-specific data -- how neurons perform within a particular evaluation mechanism running on the subnet.

While the metagraph provides the overall subnet state, the mechagraph drills down into the individual mechanisms that a subnet uses to evaluate miners. A subnet can run multiple mechanisms (each identified by a `mecid`), and the mechagraph captures the incentive and consensus data specific to that mechanism.

This method is used by advanced analytics tools, subnet operators fine-tuning their evaluation mechanisms, and researchers studying how different mechanisms affect incentive distribution.

## Metagraph vs. Mechagraph

Understanding the distinction between metagraph and mechagraph is important:

- **Metagraph:** Aggregated subnet-level view. Contains the combined scores, emissions, and weights across all mechanisms. This is what most users interact with.
- **Mechagraph:** Mechanism-level view. Contains scores and weights specific to a single evaluation mechanism. Subnets that run multiple evaluation criteria (e.g., latency + accuracy) expose separate mechagraphs for each.

For subnets with a single mechanism (mecid=0), the mechagraph is essentially identical to the metagraph. Multi-mechanism subnets reveal how each individual mechanism contributes to the final aggregated scores.

## SCALE Decoding

The response decodes to a `MechagraphInfo` struct using Bittensor's custom type registry.

**Using `@polkadot/api`:** Register Bittensor types including `MechagraphInfo`. The struct layout is similar to `MetagraphInfo` but includes the additional `mecid` field and may have fewer fields (no axon info, no coldkeys, depending on runtime version).

**Using `bittensor` Python SDK:** Use `sub.get_mechagraph(netuid=N, mecid=M)` if available in your SDK version. For older SDK versions, use the raw JSON-RPC call and decode with the `scalecodec` library.

**Key decoding notes:**

- Score fields (trust, consensus, incentive, dividends) are u16 scaled to 0--65535. Divide by 65535 for float values
- Mechanism-specific scores may differ from the aggregated metagraph scores. A miner might score high on mechanism 0 but low on mechanism 1
- The `weights` matrix in a mechagraph reflects how validators evaluate miners specifically for this mechanism
- Emissions in the mechagraph represent the portion of total subnet emissions allocated to this mechanism

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `netuid` (`INTEGER, required`): Subnet identifier.
- `mecid` (`INTEGER, required`): Mechagraph ID within the subnet.
- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getMechagraph",
    "params": [1, 0, null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded mechagraph for the requested subnet/mechid.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x001122334455"
}
```

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Fetch mechagraph for subnet 1, mechanism 0
payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getMechagraph',
    'params': [1, 0, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'Mechagraph SCALE data size: {len(scale_bytes)} bytes')
else:
    print('No mechagraph found for this subnet/mechanism')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# mechagraph = sub.get_mechagraph(netuid=1, mecid=0)
# print(f"Mechanism 0: {mechagraph.n} neurons")
```

### Full Python mechanism comparison

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'
netuid = 1

# Fetch mechagraphs for multiple mechanisms and compare
for mecid in range(3):  # Try mechanisms 0, 1, 2
    payload = {
        'jsonrpc': '2.0',
        'method': 'subnetInfo_getMechagraph',
        'params': [netuid, mecid, None],
        'id': mecid + 1
    }
    response = requests.post(url, json=payload)
    result = response.json()

    if result.get('result'):
        data_size = len(result['result']) // 2
        print(f"Mechanism {mecid}: {data_size:,} bytes of data")
    else:
        print(f"Mechanism {mecid}: not found (subnet may have fewer mechanisms)")
        break

# With bittensor SDK for deeper analysis:
# import bittensor as bt
# import numpy as np
# sub = bt.subtensor(network='finney')
#
# mech0 = sub.get_mechagraph(netuid=1, mecid=0)
# mech1 = sub.get_mechagraph(netuid=1, mecid=1)
#
# # Compare incentive scores across mechanisms
# for uid in range(min(mech0.n, mech1.n, 10)):
#     print(f"UID {uid}: mech0 incentive={mech0.I[uid]:.4f}, "
#           f"mech1 incentive={mech1.I[uid]:.4f}")
#
# # Find neurons that perform well on one mechanism but poorly on another
# divergent = np.abs(mech0.I - mech1.I) > 0.1
# print(f"Neurons with divergent mechanism scores: {divergent.sum()}")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Fetch mechagraph for subnet 1, mechanism 0
const mechagraph = await api.rpc.subnetInfo.getMechagraph(1, 0);
console.log('Raw data size:', mechagraph.toHex().length, 'bytes');

// With Bittensor type definitions registered:
// console.log('Mechanism:', mechagraph.mecid.toNumber());
// console.log('Neurons:', mechagraph.n.toNumber());

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getMechagraph",
    "params": [1, 0, null],
    "id": 1
  }'
```

## Common Use Cases

- **Advanced subnet analytics** — Analyze how individual mechanisms within a subnet distribute incentives and evaluate miners differently.
- **Mechanism tuning** — Subnet operators use mechagraph data to understand how their evaluation mechanisms are performing and adjust parameters.
- **Performance monitoring** — Track mechanism-specific trust and incentive scores for individual neurons to identify strengths across different tasks.
- **Research** — Study how multi-mechanism subnets allocate rewards and whether different mechanisms produce different consensus outcomes.
- **Validator tooling** — Build tools that help validators understand how their weights and evaluations affect mechanism-level outcomes.
- **Miner optimization** — Miners can use mechagraph data to identify which mechanisms they perform well on and optimize accordingly.

## Related Methods

- [`subnetInfo_getAllMechagraphs`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllMechagraphs) — Get mechagraphs for all subnets
- [`subnetInfo_getSelectiveMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSelectiveMechagraph) — Get filtered mechagraph data for specific neuron UIDs
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the overall metagraph for a subnet (aggregated view)
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic economic info for a subnet
- [`neuronInfo_getNeuron`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuron) — Get detailed info for a specific neuron

---

## subnetInfo_getMetagraph - Bittensor RPC Method

# subnetInfo_getMetagraph - Bittensor RPC Method

## Overview

The `subnetInfo_getMetagraph` method returns the SCALE-encoded metagraph for a specific Bittensor subnet identified by its `netuid`. The metagraph is the most important data structure in the Bittensor network -- it represents the complete topology of a subnet, including every registered neuron (validator or miner), their stakes, trust scores, incentive values, emission distributions, and weight matrices.

The metagraph is the foundation for:

- Understanding how a subnet's consensus is operating
- Monitoring validator and miner performance
- Analyzing emission flows and incentive distributions
- Building subnet explorer dashboards and analytics tools

Each subnet in Bittensor has its own metagraph. The root network (netuid 0) coordinates emissions across all subnets, while application subnets (netuid 1+) each run specialized AI/ML tasks.

## SCALE Decoding

The metagraph is one of the largest SCALE-encoded structures in Bittensor. Understanding the decoding process is important for working with it correctly.

**Using `@polkadot/api`:** Register the Bittensor type definitions including `MetagraphInfo`, `AxonInfo`, and related types. The `AxonInfo` struct typically contains: `version` (u32), `ip` (u128), `port` (u16), `ip_type` (u8), `protocol` (u8), `placeholder1` (u8), `placeholder2` (u8). IP addresses are stored as u128 and need conversion -- for IPv4, the value fits in 4 bytes.

**Using `bittensor` Python SDK:** The recommended approach is `bt.subtensor(network='finney').metagraph(netuid=N)`, which returns a `Metagraph` object with NumPy arrays for all vector fields (e.g., `meta.S` for stake, `meta.I` for incentive, `meta.E` for emission).

**Score normalization:** All u16 score fields (trust, consensus, incentive, dividends, rank, validator\_trust) are scaled to the range 0--65535. Divide by 65535 to get float values between 0.0 and 1.0. The bittensor SDK does this conversion automatically.

**Weight matrix format:** Each entry in `weights` is a sparse vector of `(target_uid, weight)` pairs. The weight values are u16 (0--65535). This represents how validators evaluate miners -- a higher weight means the validator considers that miner to be performing better.

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `netuid` (`INTEGER, required`): Subnet identifier.
- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getMetagraph",
    "params": [1, null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded metagraph for the specified subnet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xabcdef"
}
```

### Decode with Python (bittensor SDK)

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Fetch metagraph for subnet 1
payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getMetagraph',
    'params': [1, None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'Metagraph SCALE data size: {len(scale_bytes)} bytes')
else:
    print('No metagraph found for this subnet')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# meta = sub.metagraph(netuid=1)
# print(f"Subnet 1: {meta.n} neurons")
# print(f"Top validator stake: {meta.S[meta.S.argmax()]:.2f} TAO")
# print(f"Total emissions: {meta.E.sum():.4f} TAO/tempo")
```

### Full Python metagraph analysis

```python
import bittensor as bt
import numpy as np

sub = bt.subtensor(network='finney')
meta = sub.metagraph(netuid=1)

print(f"=== Subnet 1 Metagraph (block {meta.block}) ===")
print(f"Neurons: {meta.n}")
print(f"Total stake: {meta.S.sum():,.2f} TAO")
print(f"Total emissions: {meta.E.sum():,.6f} TAO/tempo")

# Identify validators (those with validator permits)
validator_mask = np.array(meta.validator_permit)
validator_uids = np.where(validator_mask)[0]
miner_uids = np.where(~validator_mask)[0]
print(f"Validators: {len(validator_uids)}, Miners: {len(miner_uids)}")

# Top 5 validators by stake
top_validators = np.argsort(meta.S[validator_mask])[::-1][:5]
print("\nTop 5 validators by stake:")
for idx in top_validators:
    uid = validator_uids[idx]
    print(f"  UID {uid}: stake={meta.S[uid]:,.2f} TAO, "
          f"vtrust={meta.Tv[uid]:.4f}, dividends={meta.D[uid]:.4f}")

# Top 5 miners by incentive
top_miners = np.argsort(meta.I[~validator_mask])[::-1][:5]
print("\nTop 5 miners by incentive:")
for idx in top_miners:
    uid = miner_uids[idx]
    print(f"  UID {uid}: incentive={meta.I[uid]:.4f}, "
          f"trust={meta.T[uid]:.4f}, emission={meta.E[uid]:.6f} TAO")

# Weight analysis: how concentrated are validator weights?
for uid in validator_uids[:3]:
    weights = meta.W[uid]
    non_zero = weights[weights > 0]
    if len(non_zero) > 0:
        print(f"\nValidator UID {uid}: sets weights on {len(non_zero)} miners")
        print(f"  Max weight: {non_zero.max():.4f}, Mean: {non_zero.mean():.4f}")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Fetch metagraph for subnet 1
const metagraph = await api.rpc.subnetInfo.getMetagraph(1);
console.log('Raw metagraph size:', metagraph.toHex().length, 'bytes');

// With proper Bittensor type definitions registered,
// the result auto-decodes to structured fields:
// console.log('Neurons:', metagraph.n.toNumber());
// console.log('Hotkeys:', metagraph.hotkeys.map(h => h.toHuman()));

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getMetagraph",
    "params": [1, null],
    "id": 1
  }'
```

ze. Cache metagraph data and refresh once per tempo for most use cases.

## Common Use Cases

- **Subnet analytics** — Build dashboards showing neuron counts, emission distributions, stake concentrations, and consensus health for each subnet.
- **Validator monitoring** — Track validator trust, consensus scores, and weight-setting patterns to detect anomalies or poor performance.
- **Miner monitoring** — Monitor miner incentive scores, rank changes, and emission earnings over time.
- **Weight analysis** — Analyze the weight matrix to understand how validators evaluate miners and detect potential gaming or collusion.
- **Staking decisions** — Use metagraph data to identify high-performing validators before delegating TAO.
- **Research** — Study incentive dynamics, consensus convergence, and network topology evolution across subnets.
- **Axon discovery** — Find miner/validator endpoints for direct network communication.

## Related Methods

- [`subnetInfo_getAllMetagraphs`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllMetagraphs) — Get metagraphs for all subnets in one call
- [`subnetInfo_getSelectiveMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSelectiveMetagraph) — Get metagraph data filtered by specific neuron UIDs
- [`subnetInfo_getMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMechagraph) — Get mechagraph for a subnet (mechanism-level view)
- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) — Get subnet configuration info
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic subnet info (emissions, registration costs)
- [`neuronInfo_getNeuron`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuron) — Get detailed info for a specific neuron by UID

---

## subnetInfo_getSelectiveMechagraph - Bittensor RPC Method

# subnetInfo_getSelectiveMechagraph - Bittensor RPC Method

## Overview

The `subnetInfo_getSelectiveMechagraph` method returns SCALE-encoded mechagraph data filtered to include only the specified neuron UIDs. This is the targeted version of `subnetInfo_getMechagraph` -- instead of returning the complete mechagraph for all neurons in a mechanism, it returns data only for the neurons you are interested in.

This method is useful when monitoring a specific set of miners or validators within a mechanism and you want to avoid downloading and parsing the full mechagraph payload. For subnets with hundreds or thousands of neurons, selective queries can significantly reduce bandwidth and processing time.

## Selective vs. Full Mechagraph

Choose the right method based on your use case:

| Scenario                                | Recommended Method                            |
| --------------------------------------- | --------------------------------------------- |
| Monitor 1--50 specific neurons          | `getSelectiveMechagraph` (this method)        |
| Analyze full mechanism topology         | [`getMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMechagraph) |
| Compare mechanisms for specific neurons | This method, called once per mecid            |
| Build complete mechanism heatmaps       | [`getMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMechagraph) |
| Real-time alerting on key neurons       | This method (lower bandwidth per poll)        |

## SCALE Decoding

The response decodes to a filtered `MechagraphInfo` struct. The structure is the same as the full mechagraph but all vector fields only contain entries for the requested UIDs, in the order they were requested.

**Using `@polkadot/api`:** Register Bittensor types including `MechagraphInfo`. The decoded result has identical field types to the full mechagraph response.

**Using `bittensor` Python SDK:** Some SDK versions support `sub.get_selective_mechagraph(netuid, mecid, uids)`. For manual decoding, use `scalecodec` with the Bittensor type registry.

**Key decoding notes:**

- The response vectors are indexed by position, not by UID. The first element corresponds to the first UID in your request, and so on
- If a requested UID does not exist in the mechanism, it may be omitted from the response or returned with zero values (depending on runtime version)
- The `weights` and `bonds` matrices for selected neurons still reference UIDs from the full subnet -- they are not re-indexed
- Score fields are u16 scaled to 0--65535; divide by 65535 for float values

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `netuid` (`INTEGER, required`): Subnet identifier.
- `start` (`INTEGER, required`): Start index for filtered mechagraph extraction.
- `mechids` (`Array, required`): List of mechagraph indexes to return.
- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSelectiveMechagraph",
    "params": [1, 0, [0, 1], null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded subset of mechagraph entries.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xdeadbeef"
}
```

### Query with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Fetch mechagraph data for neurons 0 and 1 in subnet 1, mechanism 0
payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getSelectiveMechagraph',
    'params': [1, 0, [0, 1], None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'Selective mechagraph data size: {len(scale_bytes)} bytes')
else:
    print('No data returned for specified neurons')

# Query a larger set of UIDs for batch monitoring:
# uids_to_watch = [0, 5, 12, 42, 100]
# payload['params'] = [1, 0, uids_to_watch, None]
# response = requests.post(url, json=payload)
```

### Full Python monitoring example

```python
import requests
import json
import time

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Monitor specific neurons across mechanisms
netuid = 1
watched_uids = [0, 3, 7, 15, 42]

def fetch_selective_mechagraph(netuid, mecid, uids):
    payload = {
        'jsonrpc': '2.0',
        'method': 'subnetInfo_getSelectiveMechagraph',
        'params': [netuid, mecid, uids, None],
        'id': 1
    }
    response = requests.post(url, json=payload)
    return response.json()

# Compare performance across mechanisms for watched neurons
for mecid in range(2):
    result = fetch_selective_mechagraph(netuid, mecid, watched_uids)
    if result.get('result'):
        data = result['result']
        print(f"Mechanism {mecid}: {len(data) // 2:,} bytes for {len(watched_uids)} neurons")
    else:
        print(f"Mechanism {mecid}: not available")

# With bittensor SDK for decoded analysis:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
#
# # Poll mechanism scores for watched neurons
# for mecid in [0, 1]:
#     mech = sub.get_selective_mechagraph(netuid=1, mecid=mecid, uids=watched_uids)
#     if mech:
#         for i, uid in enumerate(watched_uids):
#             print(f"  UID {uid}: incentive={mech.I[i]:.4f}, trust={mech.T[i]:.4f}")
```

### Query with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Fetch selective mechagraph for UIDs 0 and 1
const result = await api.rpc.subnetInfo.getSelectiveMechagraph(1, 0, [0, 1]);
console.log('Selective data size:', result.toHex().length, 'bytes');

// Monitor a watchlist
const watchlist = [0, 5, 12, 42, 100];
const selective = await api.rpc.subnetInfo.getSelectiveMechagraph(1, 0, watchlist);
console.log(`Data for ${watchlist.length} neurons:`, selective.toHex().length, 'bytes');

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSelectiveMechagraph",
    "params": [1, 0, [0, 1, 5, 10], null],
    "id": 1
  }'
```

zeroed | Verify UIDs exist in the subnet first |
\| Too many UIDs | No hard limit, but large requests approach full mechagraph cost | For 50+ UIDs, consider fetching the full mechagraph instead |
\| Invalid block hash | Returns JSON-RPC error | Verify block hash exists |

## Common Use Cases

- **Targeted monitoring** — Track specific miners or validators within a mechanism without downloading the entire mechagraph.
- **Performance dashboards** — Build monitoring views that focus on a user's own neurons or a watched set of neurons.
- **Bandwidth optimization** — Reduce payload size when you only need data for a small subset of the subnet's neurons.
- **Alerting systems** — Poll specific neurons' incentive and trust scores at regular intervals with minimal overhead.
- **Competitive analysis** — Monitor specific competitors' mechanism-level performance without full data retrieval.
- **Cross-mechanism comparison** — Compare how the same neurons score across different mechanisms by calling this method once per mecid.

## Related Methods

- [`subnetInfo_getMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMechagraph) — Get the full mechagraph for a subnet mechanism
- [`subnetInfo_getAllMechagraphs`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllMechagraphs) — Get mechagraphs for all subnets
- [`subnetInfo_getSelectiveMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSelectiveMetagraph) — Get filtered metagraph data for specific neuron UIDs
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the full metagraph for a subnet
- [`neuronInfo_getNeuron`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuron) — Get detailed info for a single neuron by UID

---

## subnetInfo_getSelectiveMetagraph - Bittensor RPC Method

# subnetInfo_getSelectiveMetagraph - Bittensor RPC Method

## Overview

The `subnetInfo_getSelectiveMetagraph` method returns SCALE-encoded metagraph data filtered to include only the specified neuron UIDs. This is the targeted version of `subnetInfo_getMetagraph` -- instead of returning the complete metagraph for all neurons in a subnet, it returns data only for the neurons you specify.

This method is ideal for monitoring applications that track a specific set of validators or miners. For large subnets with thousands of neurons, fetching the full metagraph on every poll is expensive in both bandwidth and processing time. The selective metagraph lets you efficiently query just the neurons you care about.

## Selective vs. Full Metagraph

Choose the right method based on your needs:

| Scenario                             | Recommended Method                          |
| ------------------------------------ | ------------------------------------------- |
| Monitor your own 1--20 neurons       | `getSelectiveMetagraph` (this method)       |
| Build a full subnet explorer         | [`getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) |
| Alert on specific neuron performance | This method (poll every tempo)              |
| Analyze entire weight matrix         | [`getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) |
| Mobile app with bandwidth limits     | This method                                 |
| Cross-subnet neuron tracking         | This method, called per subnet              |

**Bandwidth savings example:** A subnet with 256 neurons might return a 500 KB metagraph. Querying 5 specific neurons returns roughly 10--20 KB -- a 25--50x reduction.

## SCALE Decoding

The response decodes to a filtered `MetagraphInfo` struct. Vector fields are ordered by the position of UIDs in your request (not by UID value).

**Using `@polkadot/api`:** Register Bittensor types including `MetagraphInfo` and `AxonInfo`. The decoded result has identical field types to the full metagraph.

**Using `bittensor` Python SDK:** Some SDK versions support selective metagraph queries directly. For manual decoding, parse the hex as a `MetagraphInfo` struct using the Bittensor type registry.

**Key decoding notes:**

- Response vectors are positionally indexed: element 0 corresponds to the first UID you requested, element 1 to the second, and so on
- The `weights` and `bonds` sparse vectors for each neuron still reference global UIDs from the full subnet, not re-indexed positions
- If a requested UID is not registered (empty slot), it may be omitted or have `is_null: true`
- `AxonInfo` contains `ip` (u128), `port` (u16), `version` (u32), `ip_type` (u8), `protocol` (u8). IPv4 addresses fit in 4 bytes of the u128
- Score fields are u16 (0--65535). Divide by 65535 for normalized float values (0.0--1.0)

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `netuid` (`INTEGER, required`): Subnet identifier.
- `metagraphIndexes` (`Array, required`): List of metagraph indexes to return.
- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSelectiveMetagraph",
    "params": [1, [0, 1], null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded subset of metagraph entries.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xfeedbeef"
}
```

### Query with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Fetch metagraph data for neurons 0 and 1 in subnet 1
payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getSelectiveMetagraph',
    'params': [1, [0, 1], None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'Selective metagraph data size: {len(scale_bytes)} bytes')
else:
    print('No data returned for specified neurons')

# Monitor a watch list of neurons:
# my_neurons = [3, 17, 42, 88, 155]
# payload['params'] = [1, my_neurons, None]
# response = requests.post(url, json=payload)
```

### Full Python monitoring dashboard

```python
import requests
import json
import time

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Define neurons to monitor across subnets
watchlist = {
    1: [0, 3, 15, 42],      # Subnet 1: specific UIDs
    18: [0, 1, 7, 22],      # Subnet 18: specific UIDs
}

def fetch_selective(netuid, uids):
    payload = {
        'jsonrpc': '2.0',
        'method': 'subnetInfo_getSelectiveMetagraph',
        'params': [netuid, uids, None],
        'id': 1
    }
    resp = requests.post(url, json=payload, timeout=15)
    return resp.json()

# Periodic monitoring loop
for netuid, uids in watchlist.items():
    result = fetch_selective(netuid, uids)
    if result.get('result'):
        data_size = len(result['result']) // 2
        print(f"Subnet {netuid}: fetched {data_size:,} bytes for {len(uids)} neurons")
    else:
        print(f"Subnet {netuid}: no data")

# With bittensor SDK for decoded data:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
#
# for netuid, uids in watchlist.items():
#     meta = sub.metagraph(netuid=netuid)
#     for uid in uids:
#         if uid < meta.n:
#             print(f"Subnet {netuid} UID {uid}: "
#                   f"incentive={meta.I[uid]:.4f}, "
#                   f"emission={meta.E[uid]:.6f} TAO, "
#                   f"active={meta.active[uid]}, "
#                   f"last_update=block {meta.last_update[uid]}")
```

### Query with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Fetch selective metagraph for UIDs 0 and 1 on subnet 1
const result = await api.rpc.subnetInfo.getSelectiveMetagraph(1, [0, 1]);
console.log('Selective data size:', result.toHex().length, 'bytes');

// Monitor a larger watchlist
const watchlist = [0, 3, 7, 15, 42, 88, 155];
const selective = await api.rpc.subnetInfo.getSelectiveMetagraph(1, watchlist);
console.log(`Data for ${watchlist.length} neurons:`, selective.toHex().length, 'bytes');

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSelectiveMetagraph",
    "params": [1, [0, 1, 5, 10], null],
    "id": 1
  }'
```

zeroed | Get `n` from `getMetagraph` or `getSubnetsInfo` to know valid UID range |
\| Too many UIDs | No hard limit, but approaches full metagraph cost | For large sets (50+), fetch the full metagraph instead |
\| Invalid block hash | Returns JSON-RPC error | Verify block hash exists |
\| Node not synced | May return stale data | Check `system_health` |

## Common Use Cases

- **Targeted monitoring** — Track specific validators or miners within a subnet without the overhead of the full metagraph.
- **Personal dashboards** — Build monitoring views focused on a user's own registered neurons across subnets.
- **Bandwidth optimization** — Significantly reduce response sizes for large subnets when polling frequently.
- **Alerting systems** — Efficiently poll specific neurons' trust, incentive, and emission scores at regular intervals.
- **Competitive intelligence** — Monitor specific competitors' performance metrics without downloading all subnet data.
- **Mobile apps** — Keep payload sizes small for mobile-friendly subnet monitoring applications.
- **Multi-subnet tracking** — Monitor the same operator's neurons across multiple subnets by making one call per subnet.

## Related Methods

- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the full metagraph for a subnet
- [`subnetInfo_getAllMetagraphs`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllMetagraphs) — Get metagraphs for all subnets
- [`subnetInfo_getSelectiveMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSelectiveMechagraph) — Get filtered mechagraph data for specific neuron UIDs
- [`subnetInfo_getMechagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMechagraph) — Get the full mechagraph for a subnet mechanism
- [`neuronInfo_getNeuron`](https://www.dwellir.com/docs/bittensor/neuronInfo_getNeuron) — Get detailed info for a single neuron by UID

---

## subnetInfo_getSubnetHyperparams - JSON-RPC...

# subnetInfo_getSubnetHyperparams - JSON-RPC...

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns SCALE-encoded hyperparameters for the specified subnet id.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getSubnetHyperparams",
  "params": [
    1,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded subnet hyperparameter payload.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    1,
    40,
    254,
    255
  ]
}
```

---

## subnetInfo_getSubnetHyperparamsV2 - JSON-R...

# subnetInfo_getSubnetHyperparamsV2 - JSON-R...

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns updated hyperparameters for a subnet (SCALE bytes).

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getSubnetHyperparamsV2",
  "params": [
    1,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded v2 hyperparameter payload for the subnet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    1,
    40,
    254,
    255
  ]
}
```

---

## subnetInfo_getSubnetInfo - JSON-RPC Method

# subnetInfo_getSubnetInfo - JSON-RPC Method

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns SCALE-encoded info for the subnet identified by `netuid`.

## Code Examples

## Request Parameters

- `netuid` (`INTEGER, required`): Subnet identifier.
- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSubnetInfo",
    "params": [1, null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded subnet metadata and dynamic information.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1234beef"
}
```

---

## subnetInfo_getSubnetInfo_v2 - JSON-RPC Method

# subnetInfo_getSubnetInfo_v2 - JSON-RPC Method

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns V2 subnet info for `netuid`.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getSubnetInfo_v2",
  "params": [
    1,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded subnet metadata and summary fields for the requested subnet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    1,
    4,
    40,
    254
  ]
}
```

---

## subnetInfo_getSubnetsInfo - Bittensor RPC Method

# subnetInfo_getSubnetsInfo - Bittensor RPC Method

## Overview

The `subnetInfo_getSubnetsInfo` method returns SCALE-encoded configuration and metadata for all active subnets on the Bittensor network. Unlike the metagraph methods which return per-neuron topology data, this method returns the subnet-level configuration: owner, emission values, hyperparameters, and registration settings.

This is the primary method for subnet discovery -- building a list of all active subnets with their key properties. Use it to populate subnet selection UIs, build network overview dashboards, or analyze how different subnets are configured.

## SCALE Decoding

The response decodes to `Vec<Option<SubnetInfo>>` where each element corresponds to a netuid slot. Empty slots (dissolved subnets) are represented as `None`.

**Using `@polkadot/api`:** Register the `SubnetInfo` type definition from the Bittensor type registry. The decoded result is an array of optional subnet info structs. Iterate and skip `None` entries for dissolved subnets.

**Using `bittensor` Python SDK:** Use `sub.get_all_subnets_info()` which returns a list of `SubnetInfo` objects with all fields accessible as properties.

**Key decoding notes:**

- `rho` and `kappa` are consensus hyperparameters. Higher `kappa` (closer to 65535) means sharper weight consensus; lower values produce smoother distributions
- `tempo` is in blocks. At \~12 seconds per block, a tempo of 360 blocks means a consensus epoch roughly every 72 minutes
- `difficulty` is relevant only for Proof-of-Work registration. Many subnets use burn-based registration instead (check `burn` field)
- `max_allowed_uids` defines the maximum subnet capacity. When `subnetwork_n` reaches this limit, new registrations must replace existing neurons
- For live pricing, pool state, and subnet economics, use `subnetInfo_getDynamicInfo` rather than `subnetInfo_getSubnetsInfo`

## Code Examples

### Using SubstrateExamples

## Request Parameters

- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSubnetsInfo",
    "params": [null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded data for all subnets.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xaa55cc77"
}
```

### Decode with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getSubnetsInfo',
    'params': [None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result'):
    scale_bytes = result['result']
    print(f'All subnets info size: {len(scale_bytes)} bytes')
else:
    print('No subnet info returned')

# To decode with bittensor SDK:
# import bittensor as bt
# sub = bt.subtensor(network='finney')
# subnets = sub.get_all_subnets_info()
# for s in subnets:
#     print(f"Subnet {s.netuid}: neurons={s.subnetwork_n}/{s.max_n}, "
#           f"tempo={s.tempo}, emission={s.emission_value}")
```

### Full Python subnet comparison

```python
import bittensor as bt

sub = bt.subtensor(network='finney')
subnets = sub.get_all_subnets_info()

print(f"{'Netuid':>6} {'Neurons':>10} {'Max':>6} {'Tempo':>6} {'Burn (TAO)':>12} "
      f"{'Emission/day':>14} {'Immunity':>9} {'Owner':<18}")
print("-" * 95)

total_emission = 0
for s in subnets:
    if s is None:
        continue
    burn_tao = s.burn / 1e9
    daily_emission_tao = (s.emission_value / 1e9) * 7200  # ~7200 blocks/day
    total_emission += daily_emission_tao

    print(f"{s.netuid:>6} {s.subnetwork_n:>6}/{s.max_n:<4} {s.tempo:>6} "
          f"{burn_tao:>11,.2f} {daily_emission_tao:>13,.2f} {s.immunity_period:>9} "
          f"{str(s.owner)[:16]}..")

print(f"\nTotal subnets: {len([s for s in subnets if s is not None])}")
print(f"Total daily emissions: {total_emission:,.2f} TAO")

# Find subnets with available capacity
open_subnets = [s for s in subnets if s and s.subnetwork_n < s.max_n]
print(f"Subnets with open slots: {len(open_subnets)}")
for s in sorted(open_subnets, key=lambda x: x.burn):
    available = s.max_n - s.subnetwork_n
    print(f"  Subnet {s.netuid}: {available} slots available, burn={s.burn/1e9:.2f} TAO")
```

### Decode with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const subnetsInfo = await api.rpc.subnetInfo.getSubnetsInfo();
console.log('Raw data size:', subnetsInfo.toHex().length, 'bytes');

// With Bittensor types registered, iterate subnet configs:
// for (const subnet of subnetsInfo) {
//   if (!subnet.isNone) {
//     const s = subnet.unwrap();
//     console.log(`Subnet ${s.netuid}: ${s.subnetwork_n}/${s.max_n} neurons`);
//   }
// }

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSubnetsInfo",
    "params": [null],
    "id": 1
  }'
```

## Common Use Cases

- **Subnet discovery** — Build a catalog of all active subnets with their key parameters for users to browse and compare.
- **Parameter analysis** — Compare hyperparameters (tempo, difficulty, immunity period) across subnets to understand how they are configured.
- **Network overview** — Display total neurons, emission allocations, and growth trends across all subnets.
- **Registration planning** — Check registration difficulty and burn costs before deciding which subnet to register on. Find subnets with available capacity.
- **Governance monitoring** — Track subnet ownership and configuration changes over time by querying at different block hashes.
- **Emission modeling** — Analyze how emissions are distributed across subnets and predict future allocation changes.
- **Capacity planning** — Identify subnets nearing their `max_n` limit to anticipate registration competition.

## Related Methods

- [`subnetInfo_getSubnetInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetInfo) — Get configuration info for a single subnet
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic info (emissions, registration costs) for a specific subnet
- [`subnetInfo_getAllDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllDynamicInfo) — Get dynamic info for all subnets
- [`subnetInfo_getSubnetHyperparams`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetHyperparams) — Get hyperparameters for a specific subnet
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) — Get the metagraph for a specific subnet
- [`subnetInfo_getLockCost`](https://www.dwellir.com/docs/bittensor/subnetInfo_getLockCost) — Get the TAO lock cost for creating a new subnet

---

## subnetInfo_getSubnetsInfo_v2 - Bittensor RPC Method

# subnetInfo_getSubnetsInfo_v2 - Bittensor RPC Method

## Overview

The `subnetInfo_getSubnetsInfo_v2` method returns the newer subnet catalog format for the full Bittensor network. Like `subnetInfo_getSubnetsInfo`, it gives you a network-wide view of active subnets, but it is designed for newer runtimes that package more subnet state into a single SCALE payload.

Use this method when you need a single request that can drive subnet discovery, analytics backends, or control-plane tooling. It is especially useful when you want to compare many subnets at once instead of making one request per subnet.

## SCALE Decoding

The shared Dwellir endpoint returns this payload as a JSON byte array, not as a hex string. Decode it with the Bittensor type registry that matches the target runtime.

**Using `bittensor` Python SDK:** Use the SDK when you want decoded subnet information without manually working through SCALE bytes. The SDK is the most practical option for dashboards, subnet catalogs, and analytics tooling.

**Using `@polkadot/api`:** Register the relevant Bittensor subnet info types before decoding the returned byte array. This is the better fit when you are already running a TypeScript service that consumes multiple Bittensor RPC methods.

**When to prefer `v2`:**

- Use `subnetInfo_getSubnetsInfo_v2` when your tooling expects the newer subnet-info layout.
- Use `subnetInfo_getSubnetsInfo` when you need the older layout or when your decoder is already wired to the legacy type definitions.
- Use `subnetInfo_getDynamicInfo` when you only need one subnet's live economics instead of the full catalog.

## Code Examples

## Request Parameters

- `at` (`DATA, optional`): Optional block hash used as state reference.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSubnetsInfo_v2",
    "params": [null],
    "id": 1
  }'
```

## Response Fields

- `result` (`DATA, required`): `DATA` - SCALE-encoded subnet info in v2 format.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x55aa77cc"
}
```

### Query with Python

```python
import requests

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

payload = {
    'jsonrpc': '2.0',
    'method': 'subnetInfo_getSubnetsInfo_v2',
    'params': [None],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

scale_bytes = result['result']
print(f'Subnet catalog payload size: {len(scale_bytes)} bytes')

# Decode with a Bittensor-aware type registry or SDK.
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "subnetInfo_getSubnetsInfo_v2",
    "params": [null],
    "id": 1
  }'
```

## Common Use Cases

- **Subnet discovery** — Build a current list of active Bittensor subnets and their associated metadata.
- **Analytics backends** — Snapshot network-wide subnet state before deeper per-subnet processing.
- **Explorer infrastructure** — Power subnet overview pages without making dozens of individual requests.
- **Historical comparisons** — Query the catalog at a specific block hash to compare how the subnet set changed over time.

## Related Methods

- [`subnetInfo_getSubnetsInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getSubnetsInfo) -- Legacy subnet catalog method
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) -- Dynamic economics for a single subnet
- [`subnetInfo_getMetagraph`](https://www.dwellir.com/docs/bittensor/subnetInfo_getMetagraph) -- Full neuron topology for a specific subnet

---

## subnetInfo_getSubnetState - JSON-RPC Method

# subnetInfo_getSubnetState - JSON-RPC Method

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns subnet state for `netuid`.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getSubnetState",
  "params": [
    1,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded subnet state, including live registration and validator data.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    1,
    4,
    1,
    4
  ]
}
```

---

## subnetInfo_getSubnetToPrune - JSON-RPC Method

# subnetInfo_getSubnetToPrune - JSON-RPC Method

## Description

Bittensor‑specific APIs to inspect subnets: hyperparameters, dynamic state, metagraphs, mechagraphs, and pruning hints. Use to build subnet dashboards and analytics.

Returns an optional netuid scheduled to prune.

## Code Examples

## Request Parameters

- `at` (`string, optional`): Optional block hash to query historical subnet state.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "subnetInfo_getSubnetToPrune",
  "params": [
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`number, required`): Netuid selected for pruning at the requested state.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 70
}
```

---

## subscribe_newHead - Bittensor RPC Method

# subscribe_newHead - Bittensor RPC Method

Legacy alias for `chain_subscribeNewHeads`. Subscribes to new block headers via a WebSocket connection, emitting a notification each time a new best block is imported. Modern clients should use `chain_subscribeNewHeads` instead.

The initial JSON-RPC response returns a subscription ID. New-head payloads are delivered afterward as WebSocket notifications on that subscription.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "subscribe_newHead",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`string, required`): Subscription ID for the newly created legacy subscription.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "subscribe_newHead",
    "params": [],
    "id": 1
  }'
```

## Use Cases

- **Legacy client compatibility** -- Support older clients or libraries that use this alias name.
- **Real-time block tracking** -- Receive notifications for each new best block header as it is imported.

## Notes

- This is a legacy alias. Modern clients should use `chain_subscribeNewHeads`.
- Cancel with `unsubscribe_newHead` or `chain_unsubscribeNewHeads`.
- WebSocket-only; not available over HTTP.
- Dwellir-hosted Bittensor endpoints currently return `-32603 Internal error` for this legacy alias in live checks, so prefer `chain_subscribeNewHeads` for production integrations.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Canonical method for subscribing to new heads
- [`unsubscribe_newHead`](https://www.dwellir.com/docs/bittensor/unsubscribe_newHead) -- Cancel this subscription (legacy alias)
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Cancel via canonical name
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeFinalizedHeads) -- Subscribe to finalized headers instead
- [`chainHead_v1_follow`](https://www.dwellir.com/docs/bittensor/chainHead_v1_follow) -- Modern v2 chain head follow API

---

## swap_currentAlphaPrice - Bittensor RPC Method

# swap_currentAlphaPrice - Bittensor RPC Method

## Overview

The `swap_currentAlphaPrice` method returns the current alpha token price for swap calculations on the Bittensor network. In Bittensor's dynamic TAO system, each subnet has its own alpha token that can be swapped for TAO through an automated market maker (AMM) mechanism.

The alpha price represents the current exchange rate between a subnet's alpha token and TAO. This price is determined by the subnet's AMM pool state (alpha reserves and TAO reserves) and changes dynamically as swaps occur.

> **Note:** The shared Dwellir Bittensor endpoint expects a `netuid` parameter for this call. Handle unsupported subnets or runtime-specific failures as ordinary RPC errors instead of assuming a `null` response contract.

## Understanding Alpha Tokens and Dynamic TAO

In Bittensor's dynamic TAO system, each subnet operates its own internal token called "alpha." This creates a market-driven mechanism for valuing subnets:

- **Alpha tokens** represent stake within a specific subnet. When you stake TAO on a dynamic subnet, you receive alpha tokens at the current exchange rate
- **AMM pool:** Each subnet has an automated market maker pool containing reserves of both alpha tokens and TAO. The ratio of these reserves determines the price
- **Constant product formula:** The pool uses `k = alpha_in * tao_in` (similar to Uniswap v2). When TAO flows in, alpha flows out, and vice versa
- **Price impact:** Large swaps move the price more than small ones due to the constant product formula. The slippage depends on the pool depth
- **Emissions effect:** As the subnet earns emissions, TAO flows into the pool, which tends to increase the alpha price over time for well-performing subnets
- **Staking through swaps:** Staking TAO on a dynamic subnet effectively swaps TAO for alpha tokens. The alpha tokens represent your share of the subnet's stake pool

## Code Examples

### Using SubstrateExamples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "swap_currentAlphaPrice",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`Number, required`): Current ALPHA price as returned by the swap pallet.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 1.2
}
```

### Query with Python

```python
import requests
import json

url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

payload = {
    'jsonrpc': '2.0',
    'method': 'swap_currentAlphaPrice',
    'params': [1],
    'id': 1
}

response = requests.post(url, json=payload)
result = response.json()

if result.get('result') is not None:
    alpha_price = result['result']
    print(f'Current alpha price: {alpha_price}')
else:
    print('Alpha price not available (swap pallet may be disabled for this subnet)')

# For subnet-specific pricing, use subnetInfo_getDynamicInfo:
# payload = {
#     'jsonrpc': '2.0',
#     'method': 'subnetInfo_getDynamicInfo',
#     'params': [1, None],
#     'id': 2
# }
# response = requests.post(url, json=payload)
# # Decode SCALE result to get price field
```

### Full Python alpha token analysis

```python
import bittensor as bt
import requests
import json

sub = bt.subtensor(network='finney')
url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

# Get alpha price from swap RPC
payload = {
    'jsonrpc': '2.0',
    'method': 'swap_currentAlphaPrice',
    'params': [1],
    'id': 1
}
response = requests.post(url, json=payload)
swap_result = response.json()

if swap_result.get('result') is not None:
    print(f"Alpha price (swap RPC): {swap_result['result']}")

# Get detailed alpha pricing from dynamic info for each subnet
netuids = sub.get_all_subnet_netuids()

print(f"\n{'Netuid':>6} {'Dynamic':>8} {'Alpha Price':>14} {'TAO in Pool':>14} {'Alpha in Pool':>14}")
print("-" * 60)

for netuid in netuids[:20]:  # First 20 subnets
    try:
        dyn = sub.get_subnet_dynamic_info(netuid=netuid)
        if dyn and dyn.is_dynamic:
            tao_pool = dyn.tao_in / 1e9
            alpha_pool = dyn.alpha_in / 1e9
            price = tao_pool / alpha_pool if alpha_pool > 0 else 0
            print(f"{netuid:>6} {'Yes':>8} {price:>13,.6f} {tao_pool:>13,.2f} {alpha_pool:>13,.2f}")
        else:
            print(f"{netuid:>6} {'No':>8} {'N/A':>14} {'N/A':>14} {'N/A':>14}")
    except Exception as e:
        print(f"{netuid:>6} Error: {e}")

# Estimate swap output: if you want to swap X TAO for alpha
def estimate_swap_tao_for_alpha(tao_amount, tao_in_pool, alpha_in_pool):
    """Constant product AMM: (tao_in + delta) * (alpha_in - output) = k"""
    k = tao_in_pool * alpha_in_pool
    new_tao = tao_in_pool + tao_amount
    new_alpha = k / new_tao
    alpha_output = alpha_in_pool - new_alpha
    effective_price = tao_amount / alpha_output if alpha_output > 0 else 0
    slippage = (effective_price / (tao_in_pool / alpha_in_pool) - 1) * 100
    return alpha_output, effective_price, slippage

# Example: estimate swapping 100 TAO for alpha on subnet 1
dyn = sub.get_subnet_dynamic_info(netuid=1)
if dyn and dyn.is_dynamic:
    tao_pool = dyn.tao_in / 1e9
    alpha_pool = dyn.alpha_in / 1e9
    swap_amount = 100  # TAO

    alpha_out, eff_price, slippage = estimate_swap_tao_for_alpha(swap_amount, tao_pool, alpha_pool)
    spot_price = tao_pool / alpha_pool

    print(f"\n=== Swap Estimate: {swap_amount} TAO -> Alpha (Subnet 1) ===")
    print(f"Spot price: {spot_price:.6f} TAO/alpha")
    print(f"Alpha received: {alpha_out:,.4f}")
    print(f"Effective price: {eff_price:.6f} TAO/alpha")
    print(f"Price impact: {slippage:.2f}%")
```

### Query with JavaScript

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const alphaPrice = await api.rpc.swap.currentAlphaPrice(1);
  console.log('Current alpha price:', alphaPrice.toString());
} catch (err) {
  console.log('Swap RPC not available on this node');
}

await api.disconnect();
```

### Query with cURL

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "swap_currentAlphaPrice",
    "params": [1],
    "id": 1
  }'
```

## Common Use Cases

- **Subnet token pricing** — Display real-time alpha token prices for a specific subnet that uses dynamic TAO pricing.
- **Trading analysis** — Monitor alpha price movements to identify trading opportunities between TAO and subnet alpha tokens.
- **Swap UX previews** — Show users the current exchange rate before they execute a TAO-to-alpha or alpha-to-TAO swap.
- **Portfolio valuation** — Calculate the TAO-equivalent value of alpha token holdings across multiple subnets.
- **Dashboard widgets** — Display live price feeds for subnet tokens alongside other network metrics.
- **Slippage estimation** — Combine the alpha price with pool depth data from `getDynamicInfo` to estimate price impact for planned swaps.
- **Arbitrage detection** — Compare alpha prices across subnets to identify potential arbitrage opportunities.

## Related Methods

- [`swap_simSwapTaoForAlpha`](https://www.dwellir.com/docs/bittensor/swap_simSwapTaoForAlpha) — Simulate swapping TAO for alpha tokens (get estimated output)
- [`swap_simSwapAlphaForTao`](https://www.dwellir.com/docs/bittensor/swap_simSwapAlphaForTao) — Simulate swapping alpha tokens for TAO
- [`subnetInfo_getDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getDynamicInfo) — Get dynamic info including AMM pool state and alpha pricing
- [`subnetInfo_getAllDynamicInfo`](https://www.dwellir.com/docs/bittensor/subnetInfo_getAllDynamicInfo) — Get dynamic info for all subnets
- [`delegateInfo_getDelegates`](https://www.dwellir.com/docs/bittensor/delegateInfo_getDelegates) — Get all delegates (for staking yield comparison)

---

## swap_simSwapAlphaForTao - JSON-RPC Method

# swap_simSwapAlphaForTao - JSON-RPC Method

## Description

Bittensor swap helpers for TAO/ALPHA (price/simulation). Useful for quoting or UX previews; may be disabled on some nodes.

Simulates a swap from ALPHA to TAO. May return null if disabled.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `alphaAmount` (`u64, required`): Raw ALPHA amount to simulate, expressed in the smallest on-chain unit.
- `at` (`string, optional`): Optional block hash to query historical liquidity.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "swap_simSwapAlphaForTao",
  "params": [
    1,
    1000000000,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded simulation output for the ALPHA-to-TAO quote.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    7,
    122,
    166,
    0
  ]
}
```

## Error Responses

### Invalid Params

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "invalid type: string \"1000000000\", expected u64 at line 1 column 12"
  }
}
```

---

## swap_simSwapTaoForAlpha - JSON-RPC Method

# swap_simSwapTaoForAlpha - JSON-RPC Method

## Description

Bittensor swap helpers for TAO/ALPHA (price/simulation). Useful for quoting or UX previews; may be disabled on some nodes.

Simulates a swap from TAO to ALPHA. May return null if disabled or illiquid.

## Code Examples

## Request Parameters

- `netuid` (`number, required`): Numeric subnet identifier.
- `taoAmount` (`u64, required`): Raw TAO amount to simulate, expressed in the smallest on-chain unit.
- `at` (`string, optional`): Optional block hash to query historical liquidity.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "swap_simSwapTaoForAlpha",
  "params": [
    1,
    1000000000,
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): SCALE-encoded simulation output for the TAO-to-ALPHA quote.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    5,
    27,
    147,
    59
  ]
}
```

## Error Responses

### Invalid Params

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "invalid type: string \"1000000000\", expected u64 at line 1 column 12"
  }
}
```

---

## system_accountNextIndex - Bittensor RPC Method

# system_accountNextIndex - Bittensor RPC Method

Returns the next valid transaction index (nonce) for an account on Bittensor. Unlike reading the nonce directly from storage, this method accounts for pending transactions in the transaction pool, giving you the correct nonce for the next transaction you want to submit.

## Code Examples

## Request Parameters

- `accountId` (`DATA, required`): Account identifier for which to fetch the next nonce.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_accountNextIndex",
    "params": ["0x0000000000000000000000000000000000000000000000000000000000000000"],
    "id": 1
  }'
```

## Response Fields

- `result` (`INTEGER, required`): Next valid nonce (transaction index) for the account.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 15
}
```

## Use Cases

- **Transaction construction** -- Get the correct nonce before signing and submitting extrinsics (transfers, staking, subnet registrations, etc.) on Bittensor.
- **Sequential transaction submission** -- When sending multiple transactions in sequence, use this as the starting nonce and increment manually for each additional transaction.
- **Pool-aware nonce** -- Avoid "nonce too low" or "future transaction" errors by using a nonce that accounts for unconfirmed pool transactions.

## Notes

- This is the canonical method. `account_nextIndex` is an alias that returns the same result.
- The nonce includes pending pool transactions. If those transactions are dropped, the effective nonce may change.
- For high-throughput submission, consider manually tracking nonces rather than querying between each transaction.
- The account can be specified as an SS58 address or a raw hex-encoded AccountId.

## Related Methods

- [`account_nextIndex`](https://www.dwellir.com/docs/bittensor/account_nextIndex) -- Alias for this method
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Submit a signed extrinsic using the nonce
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) -- View pending transactions in the pool
- [`state_getStorage`](https://www.dwellir.com/docs/bittensor/state_getStorage) -- Read the on-chain nonce from `System.Account` (does not include pool)

---

## system_addLogFilter - Bittensor RPC Method

# system_addLogFilter - Bittensor RPC Method

Adds a log filter directive to the running Bittensor node, modifying its logging output in real time. Log filters use the same syntax as the `RUST_LOG` environment variable (e.g. `"sync=debug"`, `"runtime=trace"`). This is an administrative method that requires `--rpc-methods unsafe` and is not available on public shared RPC endpoints.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_addLogFilter",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`BOOLEAN, required`): Whether the log filter was applied successfully.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Runtime debugging** -- Temporarily increase log verbosity for specific modules to diagnose issues on a self-hosted Bittensor node.
- **Performance investigation** -- Enable trace-level logging for block import or consensus modules to investigate performance bottlenecks.
- **Selective logging** -- Add targeted filters for specific pallets or subsystems without restarting the node.

## Notes

- This is an unsafe/administrative method. Disabled on public RPC endpoints including Dwellir's shared Bittensor nodes.
- Filter directives follow the `env_logger`/`RUST_LOG` format: `target=level` (e.g. `"grandpa=trace"`, `"txpool=debug"`).
- Use `system_resetLogFilter` to revert to default logging levels.
- Adding very verbose filters (trace/debug) can significantly impact node performance.

## Related Methods

- [`system_resetLogFilter`](https://www.dwellir.com/docs/bittensor/system_resetLogFilter) -- Reset log filters to defaults
- [`system_nodeRoles`](https://www.dwellir.com/docs/bittensor/system_nodeRoles) -- Check node roles
- [`system_syncState`](https://www.dwellir.com/docs/bittensor/system_syncState) -- Check sync state for debugging

---

## system_addReservedPeer - Bittensor RPC Method

# system_addReservedPeer - Bittensor RPC Method

Adds a reserved peer to the running Bittensor node. Reserved peers are always maintained as connections -- the node will actively try to connect and reconnect to them, and they are not subject to normal peer eviction. This is an administrative method that requires `--rpc-methods unsafe`.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_addReservedPeer",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`BOOLEAN, required`): Whether the peer was added successfully.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Guaranteed connectivity** -- Ensure your Bittensor node always maintains a connection to critical peers (e.g. your own boot nodes or trusted validators).
- **Private network setup** -- Build a private or semi-private node cluster by reserving connections between known nodes.
- **Connectivity recovery** -- Add a known-good peer when a node is struggling to find peers.

## Notes

- This is an unsafe/administrative method. Disabled on public RPC endpoints including Dwellir's shared Bittensor nodes.
- Reserved peers are persistent -- the node will continue trying to connect to them even after disconnections.
- The peer multiaddr must include the peer ID (the `/p2p/12D3KooW...` component).
- Use `system_removeReservedPeer` to remove a peer from the reserved list.

## Related Methods

- [`system_removeReservedPeer`](https://www.dwellir.com/docs/bittensor/system_removeReservedPeer) -- Remove a reserved peer
- [`system_reservedPeers`](https://www.dwellir.com/docs/bittensor/system_reservedPeers) -- List current reserved peers
- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- List all currently connected peers
- [`system_localListenAddresses`](https://www.dwellir.com/docs/bittensor/system_localListenAddresses) -- Get the node's own listen addresses

---

## system_chain - Bittensor RPC Method

# system_chain - Bittensor RPC Method

Returns the chain name of the Bittensor network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`system_chain` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Network Verification** -- Confirm your application is connected to the correct Bittensor network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Bittensor"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', 'Bittensor');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/bittensor/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/bittensor/rpc_methods) -- List all available RPC methods

---

## system_chainType - JSON-RPC Method

# system_chainType - JSON-RPC Method

## Description

Returns the network environment type reported by the node (for example, `Development`, `Local`, or `Live`).

When to use it:

- Gate behavior by environment (e.g., hide faucets or disable dangerous actions on `Live`).
- Verify you are connected to the expected environment in CI, staging, or production.
- Surface readable environment context in UIs and logs.

It returns a short string such as `Live` for mainnet.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chainType",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Node environment classification such as `Development`, `Local`, or `Live`.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Live"
}
```

---

## system_health - Bittensor RPC Method

# system_health - Bittensor RPC Method

Returns the health status of the Bittensor node, including peer count, sync state, and whether the node expects to have peers.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`system_health` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Bittensor
- **Load Balancing** - Route requests only to healthy, fully synced nodes for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Bittensor:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Bittensor nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) - Get chain name
- [`system_syncState`](https://www.dwellir.com/docs/bittensor/system_syncState) - Get detailed sync progress
- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) - Get detailed peer information

---

## system_localListenAddresses - Bittensor RPC Method

# system_localListenAddresses - Bittensor RPC Method

Returns the list of multiaddr listen addresses that the Bittensor node is currently bound to. These are the addresses on which the node accepts incoming peer-to-peer connections. The response includes the protocol, IP address, port, and the node's peer ID.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_localListenAddresses",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`ARRAY, required`): List of multiaddr listen addresses configured on the node.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": ["/ip4/127.0.0.1/tcp/30333"]
}
```

## Use Cases

- **Node configuration verification** -- Confirm which interfaces and ports the node is listening on after startup.
- **Peer sharing** -- Retrieve the node's full multiaddr (including peer ID) to share with other nodes for peering.
- **Network diagnostics** -- Verify that the node is bound to the expected addresses for firewall and networking troubleshooting.

## Notes

- On public shared RPC endpoints, the returned addresses may be masked or reflect the infrastructure's internal addresses.
- The multiaddr format includes protocol, address, port, and peer ID components.
- This method is safe (read-only) and available on most node configurations.

## Related Methods

- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- List currently connected peers
- [`system_nodeRoles`](https://www.dwellir.com/docs/bittensor/system_nodeRoles) -- Get the node's configured roles
- [`system_addReservedPeer`](https://www.dwellir.com/docs/bittensor/system_addReservedPeer) -- Add a reserved peer using a multiaddr
- [`system_unstable_networkState`](https://www.dwellir.com/docs/bittensor/system_unstable_networkState) -- Detailed network diagnostics

---

## system_localPeerId - JSON-RPC Method

# system_localPeerId - JSON-RPC Method

## Description

Interact with Substrate JSON‑RPC. This method is commonly used to build reliable indexers, developer tooling, and responsive UIs.

Returns the libp2p PeerId of the node.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_localPeerId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): libp2p PeerId advertised by the connected node.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "12D3KooWKx3xLKxmyYYyL8yQ3J8A1tRmfjZGrJ43bXd7RbsKrTWd"
}
```

---

## system_name - Bittensor RPC Method

# system_name - Bittensor RPC Method

Returns the node implementation name on Bittensor. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`system_name` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Bittensor
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Bittensor node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Bittensor node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Bittensor node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Bittensor node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Bittensor node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Bittensor nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/bittensor/rpc_methods) -- List all available RPC methods

---

## system_nodeRoles - Bittensor RPC Method

# system_nodeRoles - Bittensor RPC Method

Returns the roles that the Bittensor node is configured with. Common roles include `Full` (stores and serves all chain data), `Authority` (participates in block production and consensus), and `LightClient` (only stores headers). This information helps determine the capabilities and behavior of the node you are connected to.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_nodeRoles",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`ARRAY, required`): Node role flags assigned to the current node.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": ["authority", "full_node"]
}
```

## Use Cases

- **Node capability detection** -- Determine whether the connected node is a full node, an authority (validator), or a light client before making role-specific API calls.
- **Health monitoring** -- Verify that a validator node is running with the `Authority` role as expected.
- **Client behavior adaptation** -- Adjust your application's behavior based on the node type (e.g. skip certain queries on light clients).

## Notes

- On Dwellir's shared RPC endpoints, the node role is typically `Full`.
- Authority nodes participate in block production and may have different performance characteristics.
- This method is safe (read-only) and available on all node configurations.

## Related Methods

- [`system_syncState`](https://www.dwellir.com/docs/bittensor/system_syncState) -- Check the node's sync progress
- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- List connected peers
- [`system_localListenAddresses`](https://www.dwellir.com/docs/bittensor/system_localListenAddresses) -- Get listen addresses
- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the chain name
- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) -- Get the node software version

---

## system_peers - Bittensor RPC Method

# system_peers - Bittensor RPC Method

Returns a list of peers the Bittensor node is currently connected to, including their peer ID, roles, best block information, and protocol details. This is useful for network monitoring, debugging connectivity issues, and understanding the node's position in the peer-to-peer network.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_peers",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`ARRAY, required`): Connected peers returned as peer objects.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Connectivity monitoring** -- Track the number and identity of connected peers to ensure the node is well-connected to the Bittensor network.
- **Sync diagnostics** -- Compare peer best block numbers to the node's own to diagnose sync issues.
- **Network topology** -- Build a view of the peer-to-peer network topology for monitoring dashboards.
- **Peer health checks** -- Detect when a node becomes isolated or has too few peers.

## Notes

- On public shared RPC endpoints, the peer list may be masked, truncated, or empty for security reasons.
- The method may require `--rpc-methods unsafe` on some node configurations.
- The peer count can fluctuate as connections are established and dropped.

## Related Methods

- [`system_localListenAddresses`](https://www.dwellir.com/docs/bittensor/system_localListenAddresses) -- Get the node's own listen addresses
- [`system_reservedPeers`](https://www.dwellir.com/docs/bittensor/system_reservedPeers) -- List reserved (pinned) peers
- [`system_addReservedPeer`](https://www.dwellir.com/docs/bittensor/system_addReservedPeer) -- Add a reserved peer
- [`system_syncState`](https://www.dwellir.com/docs/bittensor/system_syncState) -- Check the node's sync progress
- [`system_unstable_networkState`](https://www.dwellir.com/docs/bittensor/system_unstable_networkState) -- Detailed network state diagnostics

---

## system_properties - Bittensor RPC Method

# system_properties - Bittensor RPC Method

Returns the chain-specific properties for Bittensor, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`system_properties` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Bittensor
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Current Dwellir Values

> **Current Dwellir values:** Bittensor mainnet currently reports `TAO`, `9 decimals`, and SS58 format `42`.

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bittensor/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bittensor/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/bittensor/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/bittensor/rpc_methods) -- List all available RPC methods

---

## system_removeReservedPeer - Bittensor RPC Method

# system_removeReservedPeer - Bittensor RPC Method

Removes a peer from the reserved peer list on the running Bittensor node. After removal, the node will no longer actively maintain a connection to that peer, and the peer becomes subject to normal eviction rules. This is an administrative method that requires `--rpc-methods unsafe`.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_removeReservedPeer",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`BOOLEAN, required`): Whether the peer was removed from the reserved list successfully.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **Peer rotation** -- Remove decommissioned or misbehaving peers from the reserved list.
- **Network reconfiguration** -- Update the reserved peer set when changing your node infrastructure.
- **Troubleshooting** -- Remove a peer that is causing connectivity issues.

## Notes

- This is an unsafe/administrative method. Disabled on public RPC endpoints including Dwellir's shared Bittensor nodes.
- Removing a reserved peer does not immediately disconnect it; it just removes the reservation, making the connection subject to normal peer management.
- The peer ID is the libp2p peer identifier, not a multiaddr.

## Related Methods

- [`system_addReservedPeer`](https://www.dwellir.com/docs/bittensor/system_addReservedPeer) -- Add a reserved peer
- [`system_reservedPeers`](https://www.dwellir.com/docs/bittensor/system_reservedPeers) -- List current reserved peers
- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- List all connected peers

---

## system_reservedPeers - Bittensor RPC Method

# system_reservedPeers - Bittensor RPC Method

Returns the list of reserved peers for the Bittensor node. Reserved peers are connections that the node actively maintains -- it will always try to stay connected to them and will not evict them during peer management. These are typically set via the `--reserved-nodes` CLI flag or the `system_addReservedPeer` RPC method.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_reservedPeers",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`ARRAY, required`): Reserved peers configured on the node.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Use Cases

- **Configuration verification** -- Confirm that the expected reserved peers are configured after node startup or after adding/removing reserved peers via RPC.
- **Infrastructure monitoring** -- Track the reserved peer configuration across your Bittensor node fleet.
- **Networking diagnostics** -- Check which peers are reserved when debugging connectivity issues.

## Notes

- On public shared RPC endpoints, the reserved peer list may be empty or masked for security.
- This method may require `--rpc-methods unsafe` on some node configurations.
- Reserved peers are distinct from boot nodes; boot nodes are used for initial peer discovery, while reserved peers are permanently maintained connections.

## Related Methods

- [`system_addReservedPeer`](https://www.dwellir.com/docs/bittensor/system_addReservedPeer) -- Add a reserved peer
- [`system_removeReservedPeer`](https://www.dwellir.com/docs/bittensor/system_removeReservedPeer) -- Remove a reserved peer
- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- List all connected peers (not just reserved)
- [`system_localListenAddresses`](https://www.dwellir.com/docs/bittensor/system_localListenAddresses) -- Get the node's own listen addresses

---

## system_resetLogFilter - Bittensor RPC Method

# system_resetLogFilter - Bittensor RPC Method

Resets the node's log filter to its default configuration, removing any filters that were added at runtime via `system_addLogFilter`. This is an administrative method that requires `--rpc-methods unsafe` and is not available on public shared RPC endpoints.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_resetLogFilter",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`BOOLEAN, required`): Whether the log filter was reset successfully.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Use Cases

- **End debugging session** -- Reset log verbosity to defaults after a debugging session to restore normal log volume and node performance.
- **Reduce log noise** -- Remove verbose filters that were temporarily added for investigation.
- **Clean state** -- Ensure the log filter is in a known-good default state.

## Notes

- This is an unsafe/administrative method. Disabled on public RPC endpoints including Dwellir's shared Bittensor nodes.
- The default filter is determined by the node's startup configuration (`--log` CLI flag or `RUST_LOG` environment variable).
- Resetting the filter does not affect log output already written; it only changes future log filtering.

## Related Methods

- [`system_addLogFilter`](https://www.dwellir.com/docs/bittensor/system_addLogFilter) -- Add a log filter directive
- [`system_nodeRoles`](https://www.dwellir.com/docs/bittensor/system_nodeRoles) -- Check node roles
- [`system_syncState`](https://www.dwellir.com/docs/bittensor/system_syncState) -- Check sync progress

---

## system_syncState - Bittensor RPC Method

# system_syncState - Bittensor RPC Method

Returns the node's current synchronization progress, including the starting block, the current block, and the highest known block. This information is essential for determining whether a Bittensor node is fully synced and ready to serve accurate data.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_syncState",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`OBJECT, required`): Sync state for the node including start, current, and highest values.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "startingBlock": 900000,
    "currentBlock": 915000,
    "highestBlock": 930000
  }
}
```

## Use Cases

- **Health checks** -- Verify that a Bittensor node is fully synced before routing traffic to it. A node with `currentBlock` far below `highestBlock` is still catching up.
- **Sync progress display** -- Show sync progress bars in admin dashboards or monitoring UIs.
- **Load balancer gating** -- Only add a node to the load balancer pool once `currentBlock >= highestBlock - threshold`.
- **Alert triggers** -- Fire alerts when a node falls behind by more than a configurable number of blocks.

## Notes

- A fully synced node will have `currentBlock` equal to or very close to `highestBlock` (within 1-2 blocks).
- During warp sync, `startingBlock` may be a recent block rather than 0.
- This method is safe (read-only) and available on all node configurations.

## Related Methods

- [`system_health`](https://www.dwellir.com/docs/bittensor/system_health) -- Quick boolean check for sync and peer status
- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- List connected peers and their best block numbers
- [`system_nodeRoles`](https://www.dwellir.com/docs/bittensor/system_nodeRoles) -- Get the node's configured roles
- [`chain_getHeader`](https://www.dwellir.com/docs/bittensor/chain_getHeader) -- Get the latest block header

---

## system_unstable_networkState - Bittensor RPC Method

# system_unstable_networkState - Bittensor RPC Method

Returns detailed diagnostic information about the node's network layer, including the peer ID, listen addresses, connected peers with protocol details, and notification protocols. This method is marked as unstable, meaning its response format may change between node versions without notice.

## Code Examples

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_unstable_networkState",
    "params": [],
    "id": 1
  }'
```

## Response Fields

- `result` (`OBJECT, required`): Network diagnostics and transport state returned by this unstable API.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 12,
    "isSyncing": false
  }
}
```

## Use Cases

- **Deep network diagnostics** -- Inspect protocol-level details of peer connections, including which notification protocols are negotiated.
- **NAT and firewall debugging** -- Compare `listenedAddresses` with `externalAddresses` to detect NAT issues or misconfigured firewalls.
- **Peer protocol analysis** -- Determine which peers support which protocols (block announces, transactions, GRANDPA, etc.).

## Notes

- This API is explicitly marked as unstable. The response format may change without deprecation warnings between Substrate/Bittensor node versions.
- The response can be very large on well-connected nodes.
- May require `--rpc-methods unsafe` on some node configurations.
- On public shared RPC endpoints, the response may be masked or limited.

## Related Methods

- [`system_peers`](https://www.dwellir.com/docs/bittensor/system_peers) -- Simpler peer list with basic info
- [`system_localListenAddresses`](https://www.dwellir.com/docs/bittensor/system_localListenAddresses) -- Just the listen addresses
- [`system_syncState`](https://www.dwellir.com/docs/bittensor/system_syncState) -- Sync progress information
- [`system_nodeRoles`](https://www.dwellir.com/docs/bittensor/system_nodeRoles) -- Node role information

---

## system_version - Bittensor RPC Method

# system_version - Bittensor RPC Method

Returns the node implementation version string on Bittensor. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`system_version` is essential for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Bittensor
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Bittensor node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Bittensor node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Bittensor node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Bittensor node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Bittensor node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Bittensor nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bittensor/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bittensor/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/bittensor/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bittensor/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/bittensor/rpc_methods) -- List all available RPC methods

---

## transaction_v1_broadcast - Bittensor RPC Method

# transaction_v1_broadcast - Bittensor RPC Method

Broadcasts a signed, SCALE-encoded transaction to the Bittensor network via the new JSON-RPC v2 transaction API. Unlike the legacy `author_submitExtrinsic`, this method is designed for fire-and-forget submission -- it broadcasts the transaction to peers without waiting for pool validation results. Use `transactionWatch_v1_submitAndWatch` if you need to track the transaction lifecycle.

## Code Examples

## Request Parameters

- `transaction` (`string, required`): Hex-encoded SCALE-encoded signed transaction.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "transaction_v1_broadcast",
  "params": [
    "<transaction>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`null, required`): Acknowledges the transaction has been accepted for broadcast. Does not guarantee inclusion in a block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Transaction submission** -- Broadcast signed Bittensor transactions (TAO transfers, subnet registrations, staking operations) to the network.
- **Fire-and-forget** -- Submit transactions without maintaining a WebSocket connection to track their status.
- **High-throughput submission** -- Broadcast many transactions quickly without waiting for individual pool validation responses.

## Notes

- This method is part of the new JSON-RPC v2 specification and may not be available on all node configurations.
- A successful response only means the transaction was accepted for broadcast. It does not guarantee pool acceptance or block inclusion.
- For transaction lifecycle tracking, use `transactionWatch_v1_submitAndWatch` instead.
- The transaction must be properly signed with a valid nonce. Use `system_accountNextIndex` to get the correct nonce.

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Legacy method to submit and validate a transaction
- [`transactionWatch_v1_unwatch`](https://www.dwellir.com/docs/bittensor/transactionWatch_v1_unwatch) -- Stop watching a transaction submitted via the watch API
- [`system_accountNextIndex`](https://www.dwellir.com/docs/bittensor/system_accountNextIndex) -- Get the correct nonce for transaction construction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bittensor/author_pendingExtrinsics) -- View pending transactions in the pool

---

## transaction_v1_stop - JSON-RPC Method

# transaction_v1_stop - JSON-RPC Method

## Description

Interact with Substrate JSON‑RPC. This method is commonly used to build reliable indexers, developer tooling, and responsive UIs.

Stops a transaction processing job started previously.

## Code Examples

## Request Parameters

- `operationId` (`string, required`): Opaque operation ID returned by `transaction_v1_broadcast`.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "transaction_v1_stop",
  "params": [
    "<operationId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`null, required`): Confirms the broadcast operation is no longer being retried by the node.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": null
}
```

## Error Responses

### Invalid Operation ID

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid operation id"
  }
}
```

---

## transactionWatch_v1_submitAndWatch - JSON-...

# transactionWatch_v1_submitAndWatch - JSON-...

Submits a signed extrinsic and returns a subscription ID you can use to follow
validation, inclusion, and finalization updates. Public endpoints may reject
this method when transaction submission is disabled.

## Code Examples

## Request Parameters

- `transaction` (`string, required`): Hex-encoded SCALE extrinsic to submit and watch.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "transactionWatch_v1_submitAndWatch",
    "params": ["0xSIGNED_EXTRINSIC_HEX"],
    "id": 1
  }'
```

## Response Fields

- `result` (`string, required`): Opaque subscription ID used in subsequent `transactionWatch_v1_watchEvent` notifications and when calling `transactionWatch_v1_unwatch`.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<subscriptionId>"
}
```

## Error Responses

### Invalid Params

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params"
  }
}
```

---

## transactionWatch_v1_unwatch - Bittensor RPC Method

# transactionWatch_v1_unwatch - Bittensor RPC Method

Cancels a transaction watch subscription that was started with `transactionWatch_v1_submitAndWatch`. After calling this method, no further transaction lifecycle notifications will be delivered for that subscription. Always call this method when you are done tracking a transaction to free server-side resources.

## Code Examples

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by `transactionWatch_v1_submitAndWatch`.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "transactionWatch_v1_unwatch",
  "params": [
    "<subscriptionId>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`null, required`): Confirms the watch subscription has been cancelled.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Use Cases

- **Subscription cleanup** -- Cancel a transaction watch after the transaction has been finalized or after you have received the status you were waiting for.
- **Timeout handling** -- Stop watching a transaction that has not been included in a block within your expected timeframe.
- **Resource management** -- Free server-side resources in applications that submit many transactions.

## Notes

- This method is part of the new JSON-RPC v2 specification and operates over WebSocket connections.
- Always unwatch when done. Leaving subscriptions open consumes server memory and may count against rate limits.
- If the transaction has already been finalized or dropped, the subscription may already be inactive, but calling `unwatch` is still safe.

## Related Methods

- [`transaction_v1_broadcast`](https://www.dwellir.com/docs/bittensor/transaction_v1_broadcast) -- Broadcast a transaction without watching (fire-and-forget)
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitAndWatchExtrinsic) -- Legacy method to submit and watch a transaction
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bittensor/author_submitExtrinsic) -- Legacy submission without watching

---

## unsubscribe_newHead - Bittensor RPC Method

# unsubscribe_newHead - Bittensor RPC Method

Legacy alias for `chain_unsubscribeNewHeads`. Cancels a WebSocket subscription that was started with `subscribe_newHead` (or `chain_subscribeNewHeads`). Provide the subscription ID that was returned when the subscription was created. Modern clients should use `chain_unsubscribeNewHeads` instead.

## Request Parameters

- `subscriptionId` (`string, required`): The subscription ID returned by the subscribe call.

## Request Example

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "unsubscribe_newHead",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Response Fields

- `result` (`boolean, required`): `true` if successfully cancelled, `false` if the ID was not found.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

> This method requires a WebSocket connection and is not available over HTTP.

### WebSocket (wscat)

```bash
wscat -c wss://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -x '{
    "jsonrpc": "2.0",
    "method": "unsubscribe_newHead",
    "params": ["SUBSCRIPTION_ID"],
    "id": 1
  }'
```

## Use Cases

- **Legacy client compatibility** -- Support older clients or libraries that use this alias name for unsubscribing.
- **Subscription cleanup** -- Cancel new-head notifications when no longer needed.

## Notes

- This is a legacy alias. Modern clients should use `chain_unsubscribeNewHeads`.
- Always unsubscribe when done to free server-side resources.
- WebSocket-only; not available over HTTP.

## Related Methods

- [`subscribe_newHead`](https://www.dwellir.com/docs/bittensor/subscribe_newHead) -- Start the subscription this method cancels (legacy alias)
- [`chain_unsubscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeNewHeads) -- Canonical unsubscribe method
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bittensor/chain_subscribeNewHeads) -- Canonical subscribe method
- [`chain_unsubscribeFinalizedHeads`](https://www.dwellir.com/docs/bittensor/chain_unsubscribeFinalizedHeads) -- Cancel a finalized-heads subscription

---

## web3_clientVersion - Bittensor RPC Method

# web3_clientVersion - Bittensor RPC Method

Returns the current client software version string for your Bittensor node, including the client name, version number, OS, and runtime.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

## When to Use This Method

`web3_clientVersion` is valuable for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Bittensor client:', clientVersion);

// Using fetch
const response = await fetch('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Bittensor client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Bittensor client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/bittensor/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/bittensor/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/bittensor/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/bittensor/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Bittensor RPC Method

# web3_sha3 - Bittensor RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Bittensor.

> **Why Bittensor?** Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-bittensor-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/bittensor/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/bittensor/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/bittensor/web3_clientVersion) - Get node client version

---

## Blast RPC with Dwellir

# Blast RPC with Dwellir

## Blast RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Blast supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Blast?

Blast is a next-generation Ethereum Layer 2 solution designed for high-performance applications and DeFi protocols. Built to optimize developer and user experience, Blast offers:

### **High-Performance EVM**

- **Fast transaction finality** - Sub-second confirmation times
- **Low gas costs** - Significantly reduced fees compared to Ethereum L1
- **High throughput** - Optimized for demanding applications

### **Native Yield Generation**

- **Built-in yield** - ETH and USDB automatically earn yield
- **Developer incentives** - Gas fee rebates and yield sharing
- **Capital efficiency** - Maximize returns for users and protocols

### **Developer-First Design**

- **Full EVM compatibility** - Deploy existing Ethereum contracts seamlessly
- **Rich tooling support** - Works with Hardhat, Foundry, and all standard tools
- **Growing ecosystem** - Active developer community and partnerships

### **Decentralized & Secure**

- **Ethereum security** - Inherits L1 security properties
- **Decentralized sequencing** - Robust network architecture
- **Battle-tested infrastructure** - Proven reliability and uptime

## Quick Start with Blast

Connect to Blast in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Blast mainnet
const provider = new JsonRpcProvider(
  'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Blast mainnet
const web3 = new Web3(
  'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Blast:', chainId === 81457n);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { blast } from 'viem/chains';

// Create Blast client
const client = createPublicClient({
  chain: blast,
  transport: http('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to Blast mainnet
w3 = Web3(Web3.HTTPProvider(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection
print(f'Connected: {w3.is_connected()}')
print(f'Chain ID: {w3.eth.chain_id}')

# Get latest block number
latest_block = w3.eth.block_number
print(f'Latest block: {latest_block}')

# Get account balance
balance = w3.eth.get_balance('0x...')
print(f'Balance: {w3.from_wei(balance, "ether")} ETH')
```

## Network Information

| Parameter        | Value     | Details         |
| ---------------- | --------- | --------------- |
| Chain ID         | 81457     | Mainnet         |
| Testnet Chain ID | 168587773 | Sepolia Testnet |
| Gas Token        | ETH       | Native token    |
| RPC Standard     | Ethereum  | JSON-RPC 2.0    |

## API Reference

Blast supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/).

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Check transaction status
  if (receipt.status === 1) {
    console.log('Transaction confirmed:', receipt.transactionHash);
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Blast:

```javascript
// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Get current fee data for EIP-1559
const feeData = await provider.getFeeData();

// Prepare transaction with optimal gas settings
const optimizedTx = {
  ...tx,
  gasLimit: gasEstimate,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
};
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class BlastProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Wrong chain ID"

Verify you're connecting to the correct Blast network:

```javascript
// Check current chain ID
const chainId = await provider.send('eth_chainId', []);
console.log('Current chain ID:', parseInt(chainId, 16));

// Blast Mainnet should return 81457 (0x13e31)
// Blast Sepolia Testnet should return 168587773 (0xa0c71fd)
```

### Error: "Transaction underpriced"

Blast uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## FAQs

### What makes Blast different from other L2s?

Blast is unique in providing native yield generation for ETH and USDB holdings, along with gas fee rebates for developers and automatic capital efficiency optimizations.

### How do I bridge assets to Blast?

Use the official Blast Bridge at [blast.io/bridge](https://blast.io/bridge) or integrate with supported bridging protocols.

### Does Blast support all Ethereum tools?

Yes, Blast is fully EVM-compatible and works with all standard Ethereum development tools including Hardhat, Foundry, Remix, and MetaMask.

## Smoke Tests

Test your connection to Blast:

### curl (Mainnet)

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### curl (Testnet)

```bash
curl -X POST https://api-blast-sepolia-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Ethers.js v6

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
const network = await provider.getNetwork();

console.log('Block number:', blockNumber);
console.log('Chain ID:', network.chainId); // Should be 81457
```

### Web3.py

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

print(f'Connected: {w3.is_connected()}')
print(f'Chain ID: {w3.eth.chain_id}')  # Should be 81457
print(f'Latest block: {w3.eth.block_number}')
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Blast requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Blast)
const provider = new JsonRpcProvider(
  'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (81457)
// Note: Separate block numbers
// Lower gas fees
// Native yield generation
```

## Resources & Tools

### Official Resources

- [Blast Documentation](https://docs.blast.io)
- [Blast Bridge](https://blast.io/bridge)
- [Blast Explorer](https://blastscan.io)

### Developer Tools

- [Blast GitHub](https://github.com/blast-io)
- [Developer Portal](https://docs.blast.io/building)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Top 8 Blast RPC Providers 2026](https://www.dwellir.com/blog/best-blast-rpc-providers)

***

*Start building on Blast with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Blast RPC Method

# debug_traceBlock - Blast RPC Method

Traces all transactions in a block on Blast by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Blast - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Blast
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Blast:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Blast blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/blast/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/blast/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/blast/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/blast/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Blast RPC Method

# debug_traceBlockByHash - Blast RPC Method

Traces all transactions in a block on Blast identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Blast - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Blast
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Blast:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Blast:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/blast/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/blast/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/blast/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/blast/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/blast/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Blast RPC Method

# debug_traceBlockByNumber - Blast RPC Method

Traces all transactions in a block on Blast identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Blast - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Blast execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Blast:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Blast:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/blast/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/blast/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/blast/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/blast/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Blast RPC Method

# debug_traceCall - Blast RPC Method

Traces a call on Blast without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Blast - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Blast
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "data": "0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
        "data": "0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
        "data": "0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    data: '0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    data: '0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    'data': '0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
        "data": "0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Blast to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Blast:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Blast:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/blast/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/blast/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/blast/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/blast/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Blast RPC Method

# debug_traceTransaction - Blast RPC Method

Traces a transaction execution on Blast by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Blast
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/blast/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/blast/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Blast RPC Method

# eth_accounts - Blast RPC Method

Returns a list of addresses owned by the client on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, yield protocol builders, and teams building passive-income dApps in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/blast/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/blast/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Blast RPC Method

# eth_blockNumber - Blast RPC Method

Returns the number of the most recent block on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Syncing Applications** - Keep your dApp in sync with the latest Blast blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Blast block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Blast block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Blast block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Blast block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Blast block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Blast:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Blast:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Blast node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/blast/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/blast/eth_syncing) - Check if node is still syncing

---

## eth_call - Blast RPC Method

# eth_call - Blast RPC Method

Executes a new message call immediately without creating a transaction on Blast. Used for reading smart contract state.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Blast
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';
const walletAddress = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Blast. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Blast
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Blast

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "data": "0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "data": "0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    data := common.FromHex("0x70a08231000000000000000000000000A8b2218036Eab12e58e02f88E8825723aB4C5E5f")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Blast RPC Method

# eth_chainId - Blast RPC Method

Returns the chain ID used for transaction signing on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/blast/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/blast/eth_syncing) - Check sync status

---

## eth_coinbase - Blast RPC Method

# eth_coinbase - Blast RPC Method

Checks the legacy `eth_coinbase` compatibility method on Blast. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, yield protocol builders, and teams building passive-income dApps when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Blast coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Blast coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Blast coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Blast coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Blast coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Blast nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/blast/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/blast/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/blast/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Blast RPC Method

# eth_estimateGas - Blast RPC Method

Estimates the gas necessary to execute a transaction on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Blast
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Blast.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Blast may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "to": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/blast/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Blast RPC Method

# eth_feeHistory - Blast RPC Method

Returns historical gas fee data on Blast, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Blast without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Blast.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Blast) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/blast/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/blast/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Blast RPC Method

# eth_gasPrice - Blast RPC Method

Returns the current gas price on Blast in wei.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Blast
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Blast. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Blast, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Blast: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Blast supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/blast/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/blast/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Blast RPC Method

# eth_getBalance - Blast RPC Method

Returns the balance of a given address on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Blast
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Blast
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Blast. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Blast`);
  return balance;
}

displayBalance('0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Blast at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Blast')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Blast')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Blast.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/blast/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/blast/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Blast RPC Method

# eth_getBlockByHash - Blast RPC Method

Returns information about a block by hash on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Blast
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Blast.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Blast.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/blast/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Blast RPC Method

# eth_getBlockByNumber - Blast RPC Method

Returns information about a block by block number on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Blast
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Blast with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Blast. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/blast/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/blast/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/blast/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Blast RPC Method

# eth_getBlockReceipts - Blast RPC Method

Returns all transaction receipts for a block on Blast. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Blast, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Blast. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x645a6a1b48a2c3312d7bc389eb4f548acfbce860916e6894bd7b611d26f3de0f",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/blast/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/blast/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Blast RPC Method

# eth_getCode - Blast RPC Method

Returns the bytecode at a given address on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Blast
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Blast:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Blast:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/blast/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/blast/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Blast RPC Method

# eth_getFilterChanges - Blast RPC Method

Polls a filter on Blast for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Blast
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Blast:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/blast/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/blast/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/blast/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/blast/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/blast/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Blast RPC Method

# eth_getFilterLogs - Blast RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Blast. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Blast
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/blast/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/blast/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/blast/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/blast/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Blast RPC Method

# eth_getLogs - Blast RPC Method

Returns an array of all logs matching a given filter object on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Blast for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Blast
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Blast.

```javascript
const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Blast enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Blast, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/blast/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/blast/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Blast RPC Method

# eth_getStorageAt - Blast RPC Method

Returns the value from a storage position at a given address on Blast. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **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 yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **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": [
    "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "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-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f', '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-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';

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-blast-mainnet-archive.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 = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
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-blast-mainnet-archive.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-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    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 Blast:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.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-blast-mainnet-archive.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 = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';
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 Blast:`);
  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/blast/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/blast/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/blast/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Blast RPC Method

# eth_getTransactionByHash - Blast RPC Method

Returns the information about a transaction by transaction hash on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Blast
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Blast. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Blast. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/blast/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Blast RPC Method

# eth_getTransactionCount - Blast RPC Method

Returns the number of transactions sent from an address on Blast, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Blast
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Blast nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f'
nonce = get_transaction_count(address)
print(f'Blast nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Blast nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Blast:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/blast/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/blast/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/blast/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Blast RPC Method

# eth_getTransactionReceipt - Blast RPC Method

Returns the receipt of a transaction by transaction hash on Blast. Receipt is only available for mined transactions.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Blast and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Blast. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Blast, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x56f0fad1416d7e1ce20a18fc488c0d850c24b0bd4297f51bb901eeb24346bbe2")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/blast/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/blast/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Blast RPC Method

# eth_hashrate - Blast RPC Method

Returns the legacy `eth_hashrate` compatibility value on Blast. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Blast hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Blast hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Blast hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Blast hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Blast hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/blast/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/blast/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/blast/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Blast RPC Method

# eth_maxPriorityFeePerGas - Blast RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Blast. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Blast
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Blast priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Blast priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Blast priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Blast:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Blast:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/blast/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/blast/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/blast/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Blast RPC Method

# eth_mining - Blast RPC Method

Checks the legacy `eth_mining` compatibility method on Blast. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Blast mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Blast mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Blast mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Blast mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Blast mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/blast/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/blast/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/blast/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Blast RPC Method

# eth_newBlockFilter - Blast RPC Method

Creates a filter on Blast that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Block Monitoring** - Detect new blocks on Blast as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Blast:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/blast/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/blast/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/blast/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/blast/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Blast RPC Method

# eth_newFilter - Blast RPC Method

Creates a filter object on Blast based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Event Monitoring** - Subscribe to specific contract events on Blast such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Blast:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/blast/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/blast/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/blast/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/blast/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/blast/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Blast RPC Method

# eth_newPendingTransactionFilter - Blast RPC Method

Creates a filter on Blast that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Mempool Monitoring** - Observe unconfirmed transactions on Blast to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for yield-generating dApps, DeFi protocols with built-in returns, and gas-subsidized applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Blast...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Blast:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/blast/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/blast/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/blast/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Blast RPC Method

# eth_protocolVersion - Blast RPC Method

Returns the current Ethereum protocol version used by the Blast node.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Blast protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Blast protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Blast protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Blast protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Blast protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Blast nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/blast/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/blast/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/blast/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Blast RPC Method

# eth_sendRawTransaction - Blast RPC Method

Submits a pre-signed transaction for broadcast to Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Blast
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Blast mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/blast/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xA8b2218036Eab12e58e02f88E8825723aB4C5E5f")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/blast/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/blast/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Blast RPC Method

# eth_sendTransaction - Blast RPC Method

Creates and sends a new transaction from an unlocked account on Blast. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, yield protocol builders, and teams building passive-income dApps in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Blast tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Blast tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Blast tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Blast tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Blast tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Blast dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/blast/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/blast/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Blast RPC Method

# eth_signTransaction - Blast RPC Method

Signs a transaction with the private key of the specified account on Blast without submitting it to the network.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, yield protocol builders, and teams building passive-income dApps in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Blast tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Blast tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Blast tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Blast:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/blast/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/blast/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/blast/eth_accounts) - List accounts available for signing

---

## eth_syncing - Blast RPC Method

# eth_syncing - Blast RPC Method

Returns the sync status of your Blast node - either `false` when fully synced, or an object describing the sync progress.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Blast node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Blast node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Blast node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/blast/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/blast/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/blast/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/blast/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Blast RPC Method

# eth_uninstallFilter - Blast RPC Method

Removes a filter on Blast that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/blast/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/blast/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/blast/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/blast/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/blast/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Blast RPC Method

# net_listening - Blast RPC Method

Checks whether the connected Blast client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`net_listening` is useful for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Blast node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Blast node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Blast node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/blast/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/blast/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/blast/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/blast/web3_clientVersion) - Get node client info

---

## net_peerCount - Blast RPC Method

# net_peerCount - Blast RPC Method

Returns the number of peers currently connected to your Blast node.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`net_peerCount` is important for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Blast deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Blast peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Blast peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Blast peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Blast nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/blast/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/blast/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/blast/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/blast/web3_clientVersion) - Get node client info

---

## net_version - Blast RPC Method

# net_version - Blast RPC Method

Returns the current network ID on Blast as a decimal string. The network ID identifies which network the node is connected to.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`net_version` is essential for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Endpoint Identification** - Confirm your application is connected to the expected Blast network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Blast network ID:', networkId);

// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Blast network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Blast network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/blast/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/blast/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/blast/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/blast/eth_syncing) - Check node sync progress

---

## rpc_modules - Blast RPC Method

# rpc_modules - Blast RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Blast endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/blast/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/blast/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Blast RPC Method

# web3_clientVersion - Blast RPC Method

Returns the current client software version string for your Blast node, including the client name, version number, OS, and runtime.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Blast client:', clientVersion);

// Using fetch
const response = await fetch('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Blast client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Blast client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/blast/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/blast/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/blast/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/blast/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Blast RPC Method

# web3_sha3 - Blast RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Blast.

> **Why Blast?** Build on the only Ethereum L2 with native yield—4% for ETH and 5%+ for stablecoins automatically with $2.5B+ TVL, auto-rebasing ETH and USDB, gas revenue sharing for developers, and Blur-backed ecosystem.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, yield protocol builders, and teams building passive-income dApps:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/blast/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/blast/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/blast/web3_clientVersion) - Get node client version

---

## Boba Network - Ethereum L2 Documentation

# Boba Network - Ethereum L2 Documentation

## Boba Network RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Boba Network supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Boba Network?

Boba Network is the only multichain Layer 2 that delivers off-chain data and compute, enabling smarter applications for mass adoption. Built with hybrid blockchain technology, Boba Network offers:

### **Hybrid Technology**

- **HybridCompute** - Connect on-chain smart contracts to off-chain data and APIs
- **Up to 100x cheaper** than underlying blockchains
- **Fast finality** - Lightning-fast transactions and confirmations

### **Proven Security**

- **Optimistic Rollup** - Secured by the underlying blockchain
- **Battle-tested** - Based on proven Optimism technology
- **EVM compatible** - Full compatibility with existing Ethereum tools

### **Multichain Innovation**

- **First multichain L2** - Deployed on Ethereum and BNB Chain
- **Dual-fee tokens** - Pay fees in $BOBA or native currency
- **Growing ecosystem** - Active developer community and partnerships

## Quick Start with Boba Network

Connect to Boba Network in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Boba Network mainnet
const provider = new JsonRpcProvider(
  'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Boba Network mainnet
const web3 = new Web3(
  'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Boba Network:', chainId === 288);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';

// Create Boba Network client
const client = createPublicClient({
  chain: {
    id: 288,
    name: 'Boba Network',
    network: 'boba',
    nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
    rpcUrls: {
      default: { http: ['https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'] },
      public: { http: ['https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'] },
    },
  },
  transport: http('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value       | Details      |
| ------------ | ----------- | ------------ |
| Chain ID     | 288         | Mainnet      |
| Block Time   | \~2 seconds | Average      |
| Gas Token    | ETH         | Native token |
| RPC Standard | Ethereum    | JSON-RPC 2.0 |

## API Reference

Boba Network supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods plus hybrid compute features.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Boba Network: Check transaction details
  console.log('Transaction confirmed on Boba Network');
  console.log('Block number:', receipt.blockNumber);

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Boba Network:

```javascript
// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Get current gas price
const gasPrice = await provider.getGasPrice();

// Calculate total cost
const totalCost = gasEstimate * gasPrice;
console.log('Estimated cost:', totalCost.toString(), 'wei');
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Boba Network recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class BobaProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for gas"

Boba Network transactions require ETH for gas fees:

```javascript
// Check balance and gas requirements
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + (tx.value || 0n);

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more ETH`);
}
```

### Error: "Transaction underpriced"

Boba Network uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Boba Network requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Boba Network)
const provider = new JsonRpcProvider(
  'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (288)
// Note: Separate block numbers
// Lower gas costs
```

## Resources & Tools

### Official Resources

- [Boba Network Documentation](https://docs.boba.network)
- [Boba Gateway Bridge](https://gateway.boba.network)
- [Boba Block Explorer](https://bobascan.com)

### Developer Tools

- [Boba Network GitHub](https://github.com/bobanetwork)
- [Developer Resources](https://docs.boba.network)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Boba Network with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Boba Network RPC Method

# debug_traceBlock - Boba Network RPC Method

Traces all transactions in a block on Boba Network by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Boba Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Boba Network
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Boba Network:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Boba Network blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/boba-network/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/boba-network/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Boba Network RPC Method

# debug_traceBlockByHash - Boba Network RPC Method

Traces all transactions in a block on Boba Network identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Boba Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Boba Network
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Boba Network:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Boba Network:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/boba-network/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/boba-network/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/boba-network/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/boba-network/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Boba Network RPC Method

# debug_traceBlockByNumber - Boba Network RPC Method

Traces all transactions in a block on Boba Network identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Boba Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Boba Network execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Boba Network:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Boba Network:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/boba-network/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/boba-network/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/boba-network/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Boba Network RPC Method

# debug_traceCall - Boba Network RPC Method

Traces a call on Boba Network without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Boba Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Boba Network
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "data": "0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
        "data": "0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
        "data": "0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    data: '0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    data: '0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    'data': '0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
        "data": "0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Boba Network to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Boba Network:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Boba Network:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/boba-network/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/boba-network/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Boba Network RPC Method

# debug_traceTransaction - Boba Network RPC Method

Traces a transaction execution on Boba Network by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Boba Network
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/boba-network/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/boba-network/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Boba Network RPC Method

# eth_accounts - Boba Network RPC Method

Returns a list of addresses owned by the client on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/boba-network/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/boba-network/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Boba Network RPC Method

# eth_blockNumber - Boba Network RPC Method

Returns the number of the most recent block on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_blockNumber` is fundamental for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Syncing Applications** - Keep your dApp in sync with the latest Boba Network blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Boba Network block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Boba Network block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Boba Network block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Boba Network block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Boba Network block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Boba Network:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Boba Network:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Boba Network node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/boba-network/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/boba-network/eth_syncing) - Check if node is still syncing

---

## eth_call - Boba Network RPC Method

# eth_call - Boba Network RPC Method

Executes a new message call immediately without creating a transaction on Boba Network. Used for reading smart contract state.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

The `eth_call` method serves these key scenarios for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Boba Network
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';
const walletAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Boba Network. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Boba Network
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Boba Network

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "data": "0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "data": "0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    data := common.FromHex("0x70a08231000000000000000000000000DeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Boba Network RPC Method

# eth_chainId - Boba Network RPC Method

Returns the chain ID used for transaction signing on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_chainId` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/boba-network/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/boba-network/eth_syncing) - Check sync status

---

## eth_coinbase - Boba Network RPC Method

# eth_coinbase - Boba Network RPC Method

Checks the legacy `eth_coinbase` compatibility method on Boba Network. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Boba Network coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Boba Network coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Boba Network coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Boba Network coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Boba Network coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Boba Network nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/boba-network/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/boba-network/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/boba-network/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Boba Network RPC Method

# eth_estimateGas - Boba Network RPC Method

Estimates the gas necessary to execute a transaction on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Boba Network
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Boba Network.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Boba Network may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "to": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/boba-network/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Boba Network RPC Method

# eth_feeHistory - Boba Network RPC Method

Returns historical gas fee data on Boba Network, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Boba Network without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Boba Network.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Boba Network) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/boba-network/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/boba-network/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Boba Network RPC Method

# eth_gasPrice - Boba Network RPC Method

Returns the current gas price on Boba Network in wei.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Boba Network
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Boba Network. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Boba Network, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Boba Network: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Boba Network supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/boba-network/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/boba-network/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Boba Network RPC Method

# eth_getBalance - Boba Network RPC Method

Returns the balance of a given address on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getBalance` is fundamental for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Boba Network
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Boba Network
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Boba Network. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Boba Network`);
  return balance;
}

displayBalance('0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Boba Network at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Boba Network')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Boba Network')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Boba Network.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/boba-network/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/boba-network/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Boba Network RPC Method

# eth_getBlockByHash - Boba Network RPC Method

Returns information about a block by hash on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getBlockByHash` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Boba Network
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Boba Network.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Boba Network.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/boba-network/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Boba Network RPC Method

# eth_getBlockByNumber - Boba Network RPC Method

Returns information about a block by block number on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getBlockByNumber` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Boba Network
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Boba Network with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Boba Network. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/boba-network/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/boba-network/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/boba-network/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Boba Network RPC Method

# eth_getBlockReceipts - Boba Network RPC Method

Returns all transaction receipts for a block on Boba Network. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getBlockReceipts` is useful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Boba Network, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Boba Network. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x164c0bb90ae67c0b6c3ab90a32a8cd3917f1d3840187fb874f00f7e417dd9437",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/boba-network/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/boba-network/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Boba Network RPC Method

# eth_getCode - Boba Network RPC Method

Returns the bytecode at a given address on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getCode` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Boba Network
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Boba Network:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Boba Network:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/boba-network/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/boba-network/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Boba Network RPC Method

# eth_getFilterChanges - Boba Network RPC Method

Polls a filter on Boba Network for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getFilterChanges` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Boba Network
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Boba Network:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/boba-network/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/boba-network/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/boba-network/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/boba-network/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/boba-network/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Boba Network RPC Method

# eth_getFilterLogs - Boba Network RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Boba Network. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getFilterLogs` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Boba Network
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/boba-network/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/boba-network/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/boba-network/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/boba-network/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Boba Network RPC Method

# eth_getLogs - Boba Network RPC Method

Returns an array of all logs matching a given filter object on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Boba Network for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Boba Network
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Boba Network.

```javascript
const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Boba Network enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Boba Network, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/boba-network/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/boba-network/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Boba Network RPC Method

# eth_getStorageAt - Boba Network RPC Method

Returns the value from a storage position at a given address on Boba Network. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getStorageAt` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **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 AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **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": [
    "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "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-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', '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-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';

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-boba-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 = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
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-boba-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-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    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 Boba Network:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-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-boba-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 = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';
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 Boba Network:`);
  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/boba-network/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/boba-network/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/boba-network/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Boba Network RPC Method

# eth_getTransactionByHash - Boba Network RPC Method

Returns the information about a transaction by transaction hash on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getTransactionByHash` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Boba Network
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Boba Network. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Boba Network. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/boba-network/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Boba Network RPC Method

# eth_getTransactionCount - Boba Network RPC Method

Returns the number of transactions sent from an address on Boba Network, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getTransactionCount` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Boba Network
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Boba Network nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
nonce = get_transaction_count(address)
print(f'Boba Network nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Boba Network nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Boba Network:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/boba-network/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/boba-network/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/boba-network/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Boba Network RPC Method

# eth_getTransactionReceipt - Boba Network RPC Method

Returns the receipt of a transaction by transaction hash on Boba Network. Receipt is only available for mined transactions.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_getTransactionReceipt` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Boba Network and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Boba Network. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Boba Network, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x5d01c1b5655ee1315a49968be5bf94b730e8ea3854e88b3ee4ef7624f3b15565")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/boba-network/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/boba-network/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Boba Network RPC Method

# eth_hashrate - Boba Network RPC Method

Returns the legacy `eth_hashrate` compatibility value on Boba Network. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Boba Network hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Boba Network hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Boba Network hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Boba Network hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Boba Network hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/boba-network/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/boba-network/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/boba-network/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Boba Network RPC Method

# eth_maxPriorityFeePerGas - Boba Network RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Boba Network. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Boba Network
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Boba Network priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Boba Network priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Boba Network priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Boba Network:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Boba Network:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/boba-network/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/boba-network/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/boba-network/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Boba Network RPC Method

# eth_mining - Boba Network RPC Method

Checks the legacy `eth_mining` compatibility method on Boba Network. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Boba Network mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Boba Network mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Boba Network mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Boba Network mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Boba Network mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/boba-network/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/boba-network/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/boba-network/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Boba Network RPC Method

# eth_newBlockFilter - Boba Network RPC Method

Creates a filter on Boba Network that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_newBlockFilter` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Block Monitoring** - Detect new blocks on Boba Network as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Boba Network:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/boba-network/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/boba-network/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/boba-network/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/boba-network/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Boba Network RPC Method

# eth_newFilter - Boba Network RPC Method

Creates a filter object on Boba Network based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_newFilter` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Event Monitoring** - Subscribe to specific contract events on Boba Network such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Boba Network:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/boba-network/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/boba-network/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/boba-network/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/boba-network/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/boba-network/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Boba Network RPC Method

# eth_newPendingTransactionFilter - Boba Network RPC Method

Creates a filter on Boba Network that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Mempool Monitoring** - Observe unconfirmed transactions on Boba Network to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for AI-powered dApps, Web2 API integration, enterprise blockchain solutions, and offchain computation

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Boba Network...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Boba Network:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/boba-network/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/boba-network/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/boba-network/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Boba Network RPC Method

# eth_protocolVersion - Boba Network RPC Method

Returns the current Ethereum protocol version used by the Boba Network node.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_protocolVersion` is useful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Boba Network protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Boba Network protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Boba Network protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Boba Network protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Boba Network protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Boba Network nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/boba-network/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/boba-network/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/boba-network/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Boba Network RPC Method

# eth_sendRawTransaction - Boba Network RPC Method

Submits a pre-signed transaction for broadcast to Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Boba Network
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Boba Network mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/boba-network/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/boba-network/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/boba-network/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Boba Network RPC Method

# eth_sendTransaction - Boba Network RPC Method

Creates and sends a new transaction from an unlocked account on Boba Network. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Boba Network tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Boba Network tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Boba Network tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Boba Network tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Boba Network tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Boba Network dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/boba-network/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/boba-network/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Boba Network RPC Method

# eth_signTransaction - Boba Network RPC Method

Signs a transaction with the private key of the specified account on Boba Network without submitting it to the network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Boba Network tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Boba Network tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Boba Network tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Boba Network:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/boba-network/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/boba-network/eth_accounts) - List accounts available for signing

---

## eth_syncing - Boba Network RPC Method

# eth_syncing - Boba Network RPC Method

Returns the sync status of your Boba Network node - either `false` when fully synced, or an object describing the sync progress.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_syncing` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Boba Network node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Boba Network node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Boba Network node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/boba-network/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/boba-network/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/boba-network/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/boba-network/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Boba Network RPC Method

# eth_uninstallFilter - Boba Network RPC Method

Removes a filter on Boba Network that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`eth_uninstallFilter` is important for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/boba-network/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/boba-network/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/boba-network/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/boba-network/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/boba-network/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Boba Network RPC Method

# net_listening - Boba Network RPC Method

Checks whether the connected Boba Network client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`net_listening` is useful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Boba Network node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Boba Network node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Boba Network node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/boba-network/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/boba-network/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/boba-network/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/boba-network/web3_clientVersion) - Get node client info

---

## net_peerCount - Boba Network RPC Method

# net_peerCount - Boba Network RPC Method

Returns the number of peers currently connected to your Boba Network node.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`net_peerCount` is important for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Boba Network deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Boba Network peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Boba Network peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Boba Network peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Boba Network nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/boba-network/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/boba-network/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/boba-network/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/boba-network/web3_clientVersion) - Get node client info

---

## net_version - Boba Network RPC Method

# net_version - Boba Network RPC Method

Returns the current network ID on Boba Network as a decimal string. The network ID identifies which network the node is connected to.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`net_version` is essential for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Endpoint Identification** - Confirm your application is connected to the expected Boba Network network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Boba Network network ID:', networkId);

// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Boba Network network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Boba Network network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/boba-network/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/boba-network/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/boba-network/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/boba-network/eth_syncing) - Check node sync progress

---

## rpc_modules - Boba Network RPC Method

# rpc_modules - Boba Network RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Boba Network endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`rpc_modules` is useful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/boba-network/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/boba-network/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Boba Network RPC Method

# web3_clientVersion - Boba Network RPC Method

Returns the current client software version string for your Boba Network node, including the client name, version number, OS, and runtime.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

## When to Use This Method

`web3_clientVersion` is valuable for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Boba Network client:', clientVersion);

// Using fetch
const response = await fetch('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Boba Network client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Boba Network client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/boba-network/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/boba-network/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/boba-network/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/boba-network/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Boba Network RPC Method

# web3_sha3 - Boba Network RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Boba Network.

> **Why Boba Network?** Build on the Hybrid Compute L2 enabling smart contracts to access AI models and Web2 APIs natively with HybridCompute 2.0 for native AI/API access, $70M ecosystem funding, OP Stack compatibility, and two-way offchain integration.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for AI dApp developers, enterprise integration teams, and builders requiring offchain compute access:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-boba-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/boba-network/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/boba-network/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/boba-network/web3_clientVersion) - Get node client version

---

## Bridge Hub - Polkadot Interoperability

# Bridge Hub - Polkadot Interoperability

## Bridge Hub RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Bridge Hub supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Bridge Hub?

Bridge Hub is Polkadot's system parachain dedicated to secure cross-network connectivity. It hosts bridge light clients, routing logic, and XCM tooling that allow ecosystems such as Kusama and Ethereum to interoperate without trusted third parties.

### **Trustless Finality**

- **On-chain GRANDPA & BEEFY verification** – Embedded light clients validate both Polkadot and bridged consensus, enabling permissionless relayers.
- **Optimistic root tracking** – Finality proofs are persisted so downstream chains can verify historical headers.
- **Governed suspension modes** – Bridge operators can pause lanes per pallet when anomalies are detected.

### **Multi-Chain Connectors**

- **Polkadot  Kusama routing** – Bridge Westend/Bridge Bulletin pallets exchange relay-chain and parachain headers between ecosystems.
- **Snowbridge (Polkadot  Ethereum)** – Native integration of Snowbridge pallets for ERC-20 asset movement and message passing with Ethereum mainnet.
- **Message fan-out** – Bridge Bulletin instances distribute payloads to partner chains without duplicating relayer work.

### **Specialized Pallets**

- `pallet_bridge_grandpa` – Stores bridged finality proofs and validator sets.
- `pallet_bridge_parachains` – Syncs parachain headers required for XCM and HRMP messaging.
- `pallet_bridge_messages` – Manages outbound/inbound lanes, delivery proofs, and fee accounting for cross-chain messages.
- `pallet_xcm_bridge_hub` – Provides XCM helpers for routing assets and arbitrary instructions over bridge lanes.

## Quick Start with Bridge Hub

Connect to Bridge Hub using Dwellir's low-latency infrastructure:

Dwellir maintains Bridge Hub connectivity across Polkadot environments:

- **Polkadot Bridge Hub** – Production-grade routing parachain for trustless bridging.
- **Westend Bridge Hub** – Official Polkadot testnet used for validating upgrades before mainnet rollout.
- **Paseo Bridge Hub** – Community-driven public testnet mirroring upcoming Polkadot features.
- **Kusama Bridge Hub** – Economic canary network that ships features before Polkadot.

### Installation & Setup

Direct JSON-RPC
Polkadot.js
Substrate API (Rust)
Python (py-substrate-interface)

```bash
# Discover supported RPC namespaces
curl -X POST https://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'

# Fetch latest bridged Westend block hash
curl -X POST https://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "BridgeWestendGrandpa_finalityApi_bestFinalized",
      "0x"
    ],
    "id": 2
  }'
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

// Connect to Bridge Hub
const provider = new WsProvider('wss://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Confirm we are on Bridge Hub
const [chain, version] = await Promise.all([
  api.rpc.system.chain(),
  api.rpc.system.version()
]);
console.log(`Connected to ${chain} v${version}`);

// Inspect the latest bridged Westend finality proof
const bestWestendFinality = await api.query.bridgeWestendGrandpa.bestFinalized();
console.log('Best Westend header finalized on Bridge Hub:', bestWestendFinality.toString());

// Track Snowbridge outbound lane metrics
const outboundLanes = await api.query.bridgeWestendMessages.outboundLanes.entries();
outboundLanes.slice(0, 1).forEach(([key, value]) => {
  console.log('Outbound lane', key.args[0].toString(), value.toHuman());
});
```

```rust
use jsonrpsee::rpc_params;
use substrate_api_client::{rpc::JsonrpseeClient, Api, GetBlockHash};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = JsonrpseeClient::with_url("https://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY").await?;
    let api = Api::new(client).await?;

    // Fetch parachain head
    let head = api.get_finalized_head().await?;
    println!("Latest Bridge Hub head: {head}");

    // Query BEEFY justification root published by Bridge Hub
    let beefy_head: Option<String> = api
        .rpc()
        .request("beefy_getFinalizedHead", rpc_params![])
        .await?;
    println!("Latest BEEFY finalized head: {:?}", beefy_head);

    // Inspect permissionless lane pallet state
    let storage_key = api.metadata().storage_map_key(
        "BridgeRelayersForPermissionlessLanes",
        "RelayerConfig",
        &0u32,
    )?;
    let config: Option<Vec<u8>> = api.get_storage_by_key(storage_key, None).await?;
    println!("Permissionless relayer config: {:?}", config);

    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(
    url="wss://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY"
)

chain_name = substrate.rpc_request("system_chain", [])
print("Chain:", chain_name["result"])

# Retrieve head committed to the Kusama bridge lane
best_header = substrate.query(
    module='BridgeWestendGrandpa',
    storage_function='BestFinalized'
)
print("Best bridged Westend header:", best_header)

# Check outbound message lane status for Snowbridge
lane_status = substrate.query(
    module='EthereumOutboundQueue',
    storage_function='Outbox',
    params=[0]
)
print("Snowbridge outbound lane 0 status:", lane_status.value)
```

## Network Information

| Parameter    | Value         | Details                   |
| ------------ | ------------- | ------------------------- |
| Genesis Hash | 0xdcf691b5... | Bridge Hub (Polkadot)     |
| Block Time   | 6 seconds     | Aura + Relay finality     |
| Native Token | DOT           | Fees paid via Relay Chain |
| Parachain ID | 1002          | Polkadot system parachain |

### Network Details

| Parameter            | Value                                                                | Details |
| -------------------- | -------------------------------------------------------------------- | ------- |
| Relay Chain          | Polkadot                                                             |         |
| Genesis Hash         | `0xdcf691b5a3fbe24adc99ddc959c0561b973e329b1aef4c4b22e7bb2ddecb4464` |         |
| Consensus            | Collator-produced blocks with Polkadot relay GRANDPA finality        |         |
| Bridged Counterparts | Kusama (Westend), Bridge Bulletin, Ethereum (Snowbridge)             |         |
| Security             | On-chain slashable relayer incentives via `pallet_bridge_relayers`   |         |

## API Reference

Bridge Hub exposes the standard Substrate namespaces alongside bridge-specific RPCs for GRANDPA, BEEFY, and Snowbridge messaging. Public `bridge_*` proof namespaces are not yet exposed on current nodes.

## Bridge Protocols

### Snowbridge (Ethereum  Polkadot)

- **BEEFY light client** verifies Ethereum finality proofs and publishes outbound commitments.
- **Inbound queue** accepts ERC-20 and arbitrary message payloads via event proofs.
- **Outbound queue** batches Polkadot-origin messages and anchors them on Ethereum.

### Kusama Bridge (Westend  Polkadot)

- **BridgeWestendGrandpa** pallet syncs Westend finality headers and validator sets.
- **BridgeWestendParachains** tracks parachain heads to validate XCM and HRMP messages.
- **BridgeWestendMessages** exposes lane metrics, delivery confirmations, and fee accounting.

### Bridge Bulletin

- **Polkadot Bulletin** acts as a hub-and-spoke relay for partners requiring broadcast style delivery.
- **Permissionless lanes** allow new chains to request connectivity without runtime upgrades.

## XCM Integration

Bridge Hub exposes `pallet_xcm_bridge_hub` helpers for routing XCM messages over bridge lanes.

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

const api = await ApiPromise.create({
  provider: new WsProvider('wss://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY')
});

const laneId = 0; // Snowbridge outbound lane
const beneficiary = {
  parents: 2,
  interior: { X1: { AccountId32: { network: 'Any', id: '0x...' } } }
};
const assets = {
  parents: 1,
  interior: 'Here'
};

const tx = api.tx.xcmBridgeHub.sendAssetsOverBridge(
  laneId,
  beneficiary,
  assets,
  new BN('100000000000'),
  'Unlimited'
);

await tx.signAndSend('//Alice', ({ status }) => {
  if (status.isInBlock) {
    console.log('Bridge XCM submitted in block', status.asInBlock.toString());
  }
});
```

## Development Guides

### 1. Finality Relayer Checklist

- Subscribe to `bridgeWestendGrandpa.bestFinalized` and `bridgePolkadotBulletinGrandpa.bestFinalized` storage changes.
- Submit new proofs via `BridgeGrandpa.submit_finality_proof` extrinsics when headers advance by configured intervals.
- Monitor `pallet_bridge_relayers::Rewards` to reconcile payments.

### 2. Message Relayer Operations

- Watch `bridgeWestendMessages.outboundLanes(laneId)` for `latest_generated_nonce` vs `latest_received_nonce`.
- When public proof RPCs are released, fetch Merkle lane proofs before submitting to bridged chains (currently relayers must build proofs off-chain).
- Handle rejections by inspecting `bridgeHub` events: `MessageDispatched` and `MessageRejected`.

### 3. Observability & Alerting

- Track BEEFY justifications with `beefy_subscribeJustifications` for Snowbridge health.
- Use `state_traceBlock` on Bridge Hub to replay block execution when diagnosing bridge stalls.
- Surface metrics such as `MessageQueue.Processed` events to confirm queue throughput.

## Monitoring & Troubleshooting

| Scenario                       | Diagnostic Steps                                                                | Resolution                                                         |
| ------------------------------ | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Lane backpressure              | Compare `latest_generated_nonce` and `latest_confirmed_nonce` on outbound lanes | Increase relayer frequency or investigate failed proofs            |
| Proof rejected on target chain | Rebuild proofs off-chain and verify against the target runtime                  | Re-submit with corrected payload or wait for next finalized header |
| BEEFY stalled                  | Check `beefy_subscribeJustifications` stream and collator logs                  | Restart Snowbridge relayer or investigate validator availability   |

With Dwellir endpoints you get globally replicated infrastructure, WebSocket support for proof streaming, and archive access for rebuilding historical proofs.

---

## author_pendingExtrinsics - Bridge Hub RPC Method

# author_pendingExtrinsics - Bridge Hub RPC Method

Returns all pending extrinsics currently in the transaction pool on Bridge Hub. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`author_pendingExtrinsics` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Bridge Hub
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Bridge Hub transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bridge-hub/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/bridge-hub/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/bridge-hub/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Bridge Hub RPC Method

# author_rotateKeys - Bridge Hub RPC Method

Generate a new set of session keys on Bridge Hub. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`author_rotateKeys` is critical for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Validator Setup** - Generate initial session keys when setting up a new validator on trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Bridge Hub:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bridge-hub/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bridge-hub/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Bridge Hub RPC Method

# author_submitAndWatchExtrinsic - Bridge Hub RPC Method

Submits a signed extrinsic to Bridge Hub and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Bridge Hub
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://bridge-hub-polkadot-rpc.n.dwellir.com

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://bridge-hub-polkadot-rpc.n.dwellir.com');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://bridge-hub-polkadot-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://bridge-hub-polkadot-rpc.n.dwellir.com").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bridge-hub/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bridge-hub/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/bridge-hub/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Bridge Hub RPC Method

# author_submitExtrinsic - Bridge Hub RPC Method

Submits a fully signed extrinsic to Bridge Hub for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`author_submitExtrinsic` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Token Transfers** -- Send native tokens or assets between accounts on Bridge Hub
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://bridge-hub-polkadot-rpc.n.dwellir.com").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bridge-hub/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/bridge-hub/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Bridge Hub RPC Method

# beefy_getFinalizedHead - Bridge Hub RPC Method

Returns the block hash of the latest BEEFY-finalized block on Bridge Hub. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`beefy_getFinalizedHead` is important for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/bridge-hub/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Bridge Hub RPC Method

# chain_getBlock - Bridge Hub RPC Method

Retrieves complete block information from Bridge Hub, including the block header, extrinsics, and justifications.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/bridge-hub/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/bridge-hub/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Bridge Hub RPC Method

# chain_getBlockHash - Bridge Hub RPC Method

Returns the block hash for a given block number on Bridge Hub. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`chain_getBlockHash` is fundamental for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Bridge Hub
- **Block Navigation** - Navigate the blockchain history for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Bridge Hub
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Bridge Hub for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Bridge Hub state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Bridge Hub network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/bridge-hub/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Bridge Hub RPC Method

# chain_getFinalizedHead - Bridge Hub RPC Method

Returns the hash of the last finalized block on Bridge Hub. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`chain_getFinalizedHead` is critical for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Bridge Hub
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://bridge-hub-polkadot-rpc.n.dwellir.com', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Bridge Hub:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bridge-hub/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/bridge-hub/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Bridge Hub RPC Method

# chain_getHeader - Bridge Hub RPC Method

Returns the block header for a given hash on Bridge Hub. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`chain_getHeader` is ideal for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Bridge Hub
- **Chain Synchronization** - Track block production and monitor chain progress for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Bridge Hub:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Bridge Hub chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Bridge Hub block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bridge-hub/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Bridge Hub RPC Method

# chain_subscribeFinalizedHeads - Bridge Hub RPC Method

Subscribe to receive notifications when blocks are finalized on Bridge Hub. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Exchange Deposits** - Only credit funds after finalization for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://bridge-hub-polkadot-rpc.n.dwellir.com`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://bridge-hub-polkadot-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://bridge-hub-polkadot-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Bridge Hub:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/bridge-hub/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Bridge Hub RPC Method

# chain_subscribeNewHeads - Bridge Hub RPC Method

Subscribe to receive notifications when new block headers are produced on Bridge Hub. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`chain_subscribeNewHeads` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Block Monitoring** - Track new blocks in real time on Bridge Hub for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://bridge-hub-polkadot-rpc.n.dwellir.com`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://bridge-hub-polkadot-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://bridge-hub-polkadot-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Bridge Hub as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Bridge Hub:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/bridge-hub/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/bridge-hub/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Bridge Hub RPC Method

# grandpa_roundState - Bridge Hub RPC Method

Returns the state of the current GRANDPA finality round on Bridge Hub when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`grandpa_roundState` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Bridge Hub, critical for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/bridge-hub/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/bridge-hub/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Bridge Hub RPC Method

# payment_queryFeeDetails - Bridge Hub RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Bridge Hub. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`payment_queryFeeDetails` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Bridge Hub
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/bridge-hub/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/bridge-hub/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bridge-hub/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/bridge-hub/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Bridge Hub RPC Method

# payment_queryInfo - Bridge Hub RPC Method

Estimates the fee for an encoded extrinsic on Bridge Hub. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`payment_queryInfo` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Bridge Hub
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/bridge-hub/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/bridge-hub/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/bridge-hub/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/bridge-hub/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Bridge Hub RPC Method

# rpc_methods - Bridge Hub RPC Method

Returns a list of all RPC methods exposed by the Bridge Hub node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`rpc_methods` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Bridge Hub node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Bridge Hub endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://bridge-hub-polkadot-rpc.n.dwellir.com', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Bridge Hub endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bridge-hub/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bridge-hub/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Bridge Hub RPC Method

# state_call - Bridge Hub RPC Method

Calls a runtime API function on Bridge Hub and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`state_call` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bridge-hub/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bridge-hub/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/bridge-hub/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-bridge-hub-polkadot.n.dwellir.com/YOUR_API_KEY') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/bridge-hub/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/bridge-hub/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - Bridge Hub RPC Method

# state_getKeysPaged - Bridge Hub RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Bridge Hub. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`state_getKeysPaged` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Bridge Hub
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://bridge-hub-polkadot-rpc.n.dwellir.com";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bridge-hub/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bridge-hub/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Bridge Hub RPC Method

# state_getMetadata - Bridge Hub RPC Method

Returns the runtime metadata for Bridge Hub as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`state_getMetadata` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Bridge Hub
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Bridge Hub:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Bridge Hub:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bridge-hub/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/bridge-hub/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Bridge Hub RPC Method

# state_getRuntimeVersion - Bridge Hub RPC Method

Returns the runtime version information for Bridge Hub, including the spec name, spec version, implementation version, and supported API versions.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`state_getRuntimeVersion` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Bridge Hub
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Bridge Hub in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/bridge-hub/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Bridge Hub RPC Method

# state_getStorage - Bridge Hub RPC Method

Returns the SCALE-encoded storage value for a given key on Bridge Hub. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`state_getStorage` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Bridge Hub
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/bridge-hub/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/bridge-hub/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Bridge Hub RPC Method

# state_queryStorageAt - Bridge Hub RPC Method

Queries multiple storage keys at a specific block on Bridge Hub, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`state_queryStorageAt` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Bridge Hub
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/bridge-hub/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/bridge-hub/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/bridge-hub/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/bridge-hub/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Bridge Hub RPC Method

# system_chain - Bridge Hub RPC Method

Returns the chain name of the Bridge Hub network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`system_chain` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Network Verification** -- Confirm your application is connected to the correct Bridge Hub network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Bridge Hub"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://bridge-hub-polkadot-rpc.n.dwellir.com', 'Bridge Hub');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/bridge-hub/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/bridge-hub/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bridge-hub/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/bridge-hub/rpc_methods) -- List all available RPC methods

---

## system_health - Bridge Hub RPC Method

# system_health - Bridge Hub RPC Method

Returns the health status of the Bridge Hub node, including peer count, sync state, and whether the node expects to have peers.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`system_health` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Bridge Hub
- **Load Balancing** - Route requests only to healthy, fully synced nodes for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://bridge-hub-polkadot-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://bridge-hub-polkadot-rpc.n.dwellir.com"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Bridge Hub:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Bridge Hub nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://bridge-hub-polkadot-rpc.n.dwellir.com')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/bridge-hub/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Bridge Hub RPC Method

# system_name - Bridge Hub RPC Method

Returns the node implementation name on Bridge Hub. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`system_name` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Bridge Hub
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Bridge Hub node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Bridge Hub node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Bridge Hub node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
name = substrate.rpc_request('system_name', [])['result']
print(f'Bridge Hub node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Bridge Hub node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Bridge Hub nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/bridge-hub/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/bridge-hub/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bridge-hub/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/bridge-hub/rpc_methods) -- List all available RPC methods

---

## system_properties - Bridge Hub RPC Method

# system_properties - Bridge Hub RPC Method

Returns the chain-specific properties for Bridge Hub, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`system_properties` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Bridge Hub
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bridge-hub/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bridge-hub/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/bridge-hub/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/bridge-hub/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/bridge-hub/rpc_methods) -- List all available RPC methods

---

## system_version - Bridge Hub RPC Method

# system_version - Bridge Hub RPC Method

Returns the node implementation version string on Bridge Hub. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Bridge Hub?** Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.

## When to Use This Method

`system_version` is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Bridge Hub
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://bridge-hub-polkadot-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://bridge-hub-polkadot-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Bridge Hub node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://bridge-hub-polkadot-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Bridge Hub node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://bridge-hub-polkadot-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Bridge Hub node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://bridge-hub-polkadot-rpc.n.dwellir.com')
version = substrate.rpc_request('system_version', [])['result']
print(f'Bridge Hub node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://bridge-hub-polkadot-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Bridge Hub node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Bridge Hub nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/bridge-hub/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/bridge-hub/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/bridge-hub/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/bridge-hub/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/bridge-hub/rpc_methods) -- List all available RPC methods

---

## Binance Smart Chain - BNB Chain Documentation

# Binance Smart Chain - BNB Chain Documentation

## Binance Smart Chain RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Binance Smart Chain supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Binance Smart Chain?

Binance Smart Chain (BSC) is a fast, low-cost blockchain that runs parallel to Binance Chain, offering EVM compatibility and a thriving ecosystem:

### **High Performance**

- **3-second block times** - Fast transaction confirmations
- **Low transaction costs** - Significantly cheaper than Ethereum
- **High throughput** - Handles high transaction volumes efficiently

### **EVM Compatibility**

- **Binance ecosystem** - Backed by world's largest crypto exchange
- **Ethereum compatibility** - Deploy Ethereum dApps without changes
- **Mature infrastructure** - Battle-tested with billions in TVL

### **Vibrant Ecosystem**

- **PancakeSwap** - Leading DEX with massive liquidity
- **BNB token integration** - Native support for BNB ecosystem
- **Cross-chain bridges** - Easy asset transfers from other chains

## Quick Start with Binance Smart Chain

Connect to Binance Smart Chain in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to BSC mainnet
const provider = new JsonRpcProvider(
  'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to BSC mainnet
const web3 = new Web3(
  'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to BSC:', chainId === 56);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { bsc } from 'viem/chains';

// Create BSC client
const client = createPublicClient({
  chain: bsc,
  transport: http('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 56        | Mainnet      |
| Block Time   | 3 seconds | Average      |
| Gas Token    | BNB       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Binance Smart Chain supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with EVM compatibility. Access all standard Ethereum methods on the BNB ecosystem.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently on BSC:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // BSC has fast 3-second block times
  console.log('Transaction confirmed in block:', receipt.blockNumber);
  console.log('Gas used:', receipt.gasUsed.toString());

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Binance Smart Chain:

```javascript
// Estimate gas for BSC transaction
const gasEstimate = await provider.estimateGas(tx);

// Get current gas price (BSC uses standard gas pricing)
const gasPrice = await provider.getGasPrice();

// Calculate total cost in BNB
const totalCost = gasEstimate * gasPrice;
console.log('Total cost in BNB:', formatEther(totalCost));
```

### Event Filtering

Efficiently query contract events on BSC:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 5000; // BSC can handle larger batch sizes

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class BSCProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds"

BSC transactions require BNB for gas fees:

```javascript
// Check BNB balance for gas fees
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  const needed = formatEther(totalRequired - balance);
  throw new Error(`Need ${needed} more BNB`);
}
```

### Error: "Transaction underpriced"

BSC uses legacy gas pricing. Use current gas price:

```javascript
// Get current gas price
const gasPrice = await provider.getGasPrice();

const tx = {
  to: recipient,
  value: amount,
  gasPrice: gasPrice,
  gasLimit: 21000n,
  type: 0 // Legacy transaction type
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from Ethereum to Binance Smart Chain requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (BSC)
const provider = new JsonRpcProvider(
  'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (56)
// Note: Separate block numbers
// Note: Different gas token (BNB instead of ETH)
// Note: Legacy gas pricing (no EIP-1559)
```

## Resources & Tools

### Official Resources

- [BSC Documentation](https://docs.bnbchain.org/)
- [BSC Bridge](https://www.bnbchain.org/en/bridge)
- [BscScan Block Explorer](https://bscscan.com/)

### Developer Tools

- [Developer Tools](https://docs.bnbchain.org/)
- [Remix IDE](https://remix.ethereum.org/)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Binance Smart Chain with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - BSC RPC Method

# debug_traceBlock - BSC RPC Method

Traces all transactions in a block on Binance Smart Chain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

BSC API endpoints are full nodes with debug APIs enabled. Debug methods work for blocks and transactions whose state is still retained on the node. Older historical state requires an archive node, available as a dedicated node cluster.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on BSC
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on BSC:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in BSC blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/bsc/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/bsc/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/bsc/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/bsc/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - BSC RPC Method

# debug_traceBlockByHash - BSC RPC Method

Traces all transactions in a block on Binance Smart Chain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

BSC API endpoints are full nodes with debug APIs enabled. Debug methods work for blocks and transactions whose state is still retained on the node. Older historical state requires an archive node, available as a dedicated node cluster.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on BSC
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on BSC:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on BSC:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/bsc/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/bsc/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/bsc/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/bsc/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bsc/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - BSC RPC Method

# debug_traceBlockByNumber - BSC RPC Method

Traces all transactions in a block on Binance Smart Chain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

BSC API endpoints are full nodes with debug APIs enabled. Debug methods work for blocks and transactions whose state is still retained on the node. Older historical state requires an archive node, available as a dedicated node cluster.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of BSC execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on BSC:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on BSC:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/bsc/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/bsc/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/bsc/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/bsc/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - BSC RPC Method

# debug_traceCall - BSC RPC Method

Traces a call on Binance Smart Chain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

BSC API endpoints are full nodes with debug APIs enabled. Debug methods work for blocks and transactions whose state is still retained on the node. Older historical state requires an archive node, available as a dedicated node cluster.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on BSC
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "data": "0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
        "data": "0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
        "data": "0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    data: '0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    data: '0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    'data': '0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
        "data": "0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on BSC to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on BSC:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on BSC:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/bsc/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/bsc/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/bsc/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/bsc/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - BSC RPC Method

# debug_traceTransaction - BSC RPC Method

Traces a transaction execution on Binance Smart Chain by transaction hash.

BSC API endpoints are full nodes with debug APIs enabled. Debug methods work for blocks and transactions whose state is still retained on the node. Older historical state requires an archive node, available as a dedicated node cluster.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on BSC
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/bsc/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/bsc/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - BSC RPC Method

# eth_accounts - BSC RPC Method

Returns a list of addresses owned by the client on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/bsc/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/bsc/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - BSC RPC Method

# eth_blockNumber - BSC RPC Method

Returns the number of the most recent block on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Syncing Applications** - Keep your dApp in sync with the latest BSC blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('BSC block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('BSC block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'BSC block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'BSC block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("BSC block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on BSC:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on BSC:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your BSC node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bsc/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/bsc/eth_syncing) - Check if node is still syncing

---

## eth_call - BSC RPC Method

# eth_call - BSC RPC Method

Executes a new message call immediately without creating a transaction on Binance Smart Chain. Used for reading smart contract state.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on BSC
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';
const walletAddress = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on BSC. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on BSC
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Binance Smart Chain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "data": "0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "data": "0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    data := common.FromHex("0x70a082310000000000000000000000008894E0a0c962CB723c1976a4421c95949bE2D4E3")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - BSC RPC Method

# eth_chainId - BSC RPC Method

Returns the chain ID used for transaction signing on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/bsc/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/bsc/eth_syncing) - Check sync status

---

## eth_coinbase - BSC RPC Method

# eth_coinbase - BSC RPC Method

Checks the legacy `eth_coinbase` compatibility method on Binance Smart Chain. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('BSC coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('BSC coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'BSC coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'BSC coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("BSC coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of BSC nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/bsc/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/bsc/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/bsc/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - BSC RPC Method

# eth_estimateGas - BSC RPC Method

Estimates the gas necessary to execute a transaction on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on BSC
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x8894E0a0c962CB723c1976a4421c95949bE2D4E3', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x8894E0a0c962CB723c1976a4421c95949bE2D4E3', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on BSC.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like BSC may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "to": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x8894E0a0c962CB723c1976a4421c95949bE2D4E3', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/bsc/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - BSC RPC Method

# eth_feeHistory - BSC RPC Method

Returns historical gas fee data on Binance Smart Chain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on BSC without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on BSC.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on BSC) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/bsc/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/bsc/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - BSC RPC Method

# eth_gasPrice - BSC RPC Method

Returns the current gas price on Binance Smart Chain in wei.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on BSC
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of BSC. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on BSC, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on BSC: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if BSC supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/bsc/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/bsc/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - BSC RPC Method

# eth_getBalance - BSC RPC Method

Returns the balance of a given address on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Wallet applications**: Display user balances and enable balance-dependent operations on BSC
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Binance Smart Chain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Binance Smart Chain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} BSC`);
  return balance;
}

displayBalance('0x8894E0a0c962CB723c1976a4421c95949bE2D4E3');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on BSC at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 BSC')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 BSC')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Binance Smart Chain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/bsc/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/bsc/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - BSC RPC Method

# eth_getBlockByHash - BSC RPC Method

Returns information about a block by hash on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Binance Smart Chain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Binance Smart Chain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Binance Smart Chain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/bsc/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - BSC RPC Method

# eth_getBlockByNumber - BSC RPC Method

Returns information about a block by block number on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Binance Smart Chain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Binance Smart Chain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Binance Smart Chain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/bsc/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bsc/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bsc/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - BSC RPC Method

# eth_getBlockReceipts - BSC RPC Method

Returns all transaction receipts for a block on Binance Smart Chain. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Binance Smart Chain, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Binance Smart Chain. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc2b1f9c182513683b2358397114147563e5eb5a0be5d153487f15bb32ea559ff",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bsc/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bsc/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - BSC RPC Method

# eth_getCode - BSC RPC Method

Returns the bytecode at a given address on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on BSC
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on BSC:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on BSC:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/bsc/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/bsc/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - BSC RPC Method

# eth_getFilterChanges - BSC RPC Method

Polls a filter on Binance Smart Chain for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on BSC
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on BSC:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bsc/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/bsc/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/bsc/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bsc/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/bsc/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - BSC RPC Method

# eth_getFilterLogs - BSC RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Binance Smart Chain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on BSC
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bsc/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bsc/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/bsc/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bsc/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - BSC RPC Method

# eth_getLogs - BSC RPC Method

Returns an array of all logs matching a given filter object on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on BSC for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Binance Smart Chain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on BSC.

```javascript
const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if BSC enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Binance Smart Chain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bsc/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bsc/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - BSC RPC Method

# eth_getStorageAt - BSC RPC Method

Returns the value from a storage position at a given address on Binance Smart Chain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **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 high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **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": [
    "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "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-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x8894E0a0c962CB723c1976a4421c95949bE2D4E3', '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-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';

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-bsc-mainnet-full.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 = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
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-bsc-mainnet-full.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-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    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 BSC:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.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-bsc-mainnet-full.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 = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';
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 BSC:`);
  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/bsc/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/bsc/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/bsc/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - BSC RPC Method

# eth_getTransactionByHash - BSC RPC Method

Returns the information about a transaction by transaction hash on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Binance Smart Chain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Binance Smart Chain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Binance Smart Chain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bsc/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - BSC RPC Method

# eth_getTransactionCount - BSC RPC Method

Returns the number of transactions sent from an address on Binance Smart Chain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on BSC
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x8894E0a0c962CB723c1976a4421c95949bE2D4E3', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('BSC nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3'
nonce = get_transaction_count(address)
print(f'BSC nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("BSC nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on BSC:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/bsc/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bsc/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bsc/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - BSC RPC Method

# eth_getTransactionReceipt - BSC RPC Method

Returns the receipt of a transaction by transaction hash on Binance Smart Chain. Receipt is only available for mined transactions.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Binance Smart Chain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Binance Smart Chain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Binance Smart Chain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x15f20ca5615d94cc4685b9132ce7d5aafd5a4967197a2b3eec0bbbfef5eba10c")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bsc/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/bsc/eth_getLogs) - Query logs by filter

---

## eth_hashrate - BSC RPC Method

# eth_hashrate - BSC RPC Method

Returns the legacy `eth_hashrate` compatibility value on Binance Smart Chain. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('BSC hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('BSC hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'BSC hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'BSC hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("BSC hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/bsc/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/bsc/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/bsc/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - BSC RPC Method

# eth_maxPriorityFeePerGas - BSC RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Binance Smart Chain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on BSC
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('BSC priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'BSC priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("BSC priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on BSC:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on BSC:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/bsc/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/bsc/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/bsc/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - BSC RPC Method

# eth_mining - BSC RPC Method

Checks the legacy `eth_mining` compatibility method on Binance Smart Chain. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('BSC mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('BSC mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'BSC mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'BSC mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("BSC mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/bsc/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/bsc/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/bsc/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - BSC RPC Method

# eth_newBlockFilter - BSC RPC Method

Creates a filter on Binance Smart Chain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Block Monitoring** - Detect new blocks on BSC as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on BSC:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bsc/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bsc/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/bsc/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/bsc/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - BSC RPC Method

# eth_newFilter - BSC RPC Method

Creates a filter object on Binance Smart Chain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Event Monitoring** - Subscribe to specific contract events on BSC such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on BSC:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x8894E0a0c962CB723c1976a4421c95949bE2D4E3',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bsc/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/bsc/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/bsc/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bsc/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/bsc/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - BSC RPC Method

# eth_newPendingTransactionFilter - BSC RPC Method

Creates a filter on Binance Smart Chain that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Mempool Monitoring** - Observe unconfirmed transactions on BSC to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for high-frequency DeFi (PancakeSwap), NFT marketplaces, and GameFi applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on BSC...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on BSC:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bsc/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/bsc/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/bsc/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - BSC RPC Method

# eth_protocolVersion - BSC RPC Method

Returns the current Ethereum protocol version used by the Binance Smart Chain node.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('BSC protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('BSC protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'BSC protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'BSC protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("BSC protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of BSC nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/bsc/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/bsc/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/bsc/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - BSC RPC Method

# eth_sendRawTransaction - BSC RPC Method

Submits a pre-signed transaction for broadcast to Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to BSC
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x8894E0a0c962CB723c1976a4421c95949bE2D4E3', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the BSC mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/bsc/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/bsc/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/bsc/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - BSC RPC Method

# eth_sendTransaction - BSC RPC Method

Creates and sends a new transaction from an unlocked account on Binance Smart Chain. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('BSC tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('BSC tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'BSC tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'BSC tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("BSC tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on BSC dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/bsc/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/bsc/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - BSC RPC Method

# eth_signTransaction - BSC RPC Method

Signs a transaction with the private key of the specified account on Binance Smart Chain without submitting it to the network.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed BSC tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed BSC tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed BSC tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on BSC:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/bsc/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/bsc/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/bsc/eth_accounts) - List accounts available for signing

---

## eth_syncing - BSC RPC Method

# eth_syncing - BSC RPC Method

Returns the sync status of your Binance Smart Chain node - either `false` when fully synced, or an object describing the sync progress.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('BSC node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('BSC node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("BSC node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/bsc/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/bsc/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/bsc/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/bsc/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - BSC RPC Method

# eth_uninstallFilter - BSC RPC Method

Removes a filter on Binance Smart Chain that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/bsc/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/bsc/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/bsc/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/bsc/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/bsc/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - BSC RPC Method

# net_listening - BSC RPC Method

Checks whether the connected Binance Smart Chain client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`net_listening` is useful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('BSC node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'BSC node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("BSC node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/bsc/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/bsc/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/bsc/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/bsc/web3_clientVersion) - Get node client info

---

## net_peerCount - BSC RPC Method

# net_peerCount - BSC RPC Method

Returns the number of peers currently connected to your Binance Smart Chain node.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`net_peerCount` is important for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific BSC deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`BSC peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'BSC peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("BSC peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of BSC nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/bsc/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/bsc/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/bsc/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/bsc/web3_clientVersion) - Get node client info

---

## net_version - BSC RPC Method

# net_version - BSC RPC Method

Returns the current network ID on Binance Smart Chain as a decimal string. The network ID identifies which network the node is connected to.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`net_version` is essential for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Endpoint Identification** - Confirm your application is connected to the expected BSC network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('BSC network ID:', networkId);

// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'BSC network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("BSC network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/bsc/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/bsc/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/bsc/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/bsc/eth_syncing) - Check node sync progress

---

## rpc_modules - BSC RPC Method

# rpc_modules - BSC RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Binance Smart Chain endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/bsc/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/bsc/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - BSC RPC Method

# web3_clientVersion - BSC RPC Method

Returns the current client software version string for your Binance Smart Chain node, including the client name, version number, OS, and runtime.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('BSC client:', clientVersion);

// Using fetch
const response = await fetch('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'BSC client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("BSC client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/bsc/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/bsc/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/bsc/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/bsc/net_peerCount) - Get number of connected peers

---

## web3_sha3 - BSC RPC Method

# web3_sha3 - BSC RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Binance Smart Chain.

> **Why BSC?** Build on the third-largest blockchain by market cap with $12B+ TVL and 37%+ DEX market share with sub-$0.10 fees, 2.6M daily active users, full EVM compatibility, and direct Binance integration.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, trading platform builders, and teams seeking Binance ecosystem access:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-bsc-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/bsc/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/bsc/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/bsc/web3_clientVersion) - Get node client version

---

## Celo - Mobile-First Blockchain Platform Documentation

# Celo - Mobile-First Blockchain Platform Documentation

## Celo RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Celo supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Celo?

Celo is a mobile-first, EVM-compatible blockchain platform designed to make decentralized financial tools accessible to anyone with a mobile phone. As a carbon-negative blockchain, Celo leads the way in sustainable Web3 development.

### **Mobile-First Architecture**

- **Ultralight client** - Sync and verify on low-end smartphones
- **Phone number mapping** - Send crypto using just phone numbers
- **Gas fee abstraction** - Pay fees with any Celo native asset
- **Offline transactions** - Support for areas with limited connectivity

### **Financial Inclusion**

- **Stable value currencies** - Native stablecoins (cUSD, cEUR, cREAL)
- **Low transaction costs** - Transactions under $0.01
- **Fast finality** - 5-second block times with instant finality
- **Multi-currency gas** - Pay transaction fees in stable tokens

### **Sustainability Leadership**

- **Carbon negative** - First carbon-negative blockchain
- **Regenerative finance** - Built-in climate action programs
- **Natural capital backing** - Reserve includes tokenized rainforest
- **Climate collective** - Supporting ecosystem climate initiatives

## Quick Start with Celo

Connect to Celo in seconds with Dwellir's high-performance endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
ContractKit

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Celo mainnet
const provider = new JsonRpcProvider(
  'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query cUSD balance
const cUSD = '0x765DE816845861e75A25fCA122bb6898B8B1282a';
const balance = await provider.getBalance('0x...', cUSD);
console.log('cUSD Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Celo mainnet
const web3 = new Web3(
  'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Celo:', chainId === 42220);

// Get gas price in CELO
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { celo } from 'viem/chains';

// Create Celo client
const client = createPublicClient({
  chain: celo,
  transport: http('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'),
});

// Read stable token balance
const cUSDAddress = '0x765DE816845861e75A25fCA122bb6898B8B1282a';
const balance = await client.readContract({
  address: cUSDAddress,
  abi: erc20Abi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```javascript
import { newKit } from '@celo/contractkit';

// Connect using ContractKit (Celo's SDK)
const kit = newKit('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get stable token contracts
const cUSD = await kit.contracts.getStableToken();
const cEUR = await kit.contracts.getStableToken('cEUR');

// Get account balance in multiple currencies
const address = '0x...';
const [celoBalance, cUsdBalance] = await Promise.all([
  kit.getTotalBalance(address),
  cUSD.balanceOf(address)
]);

console.log('CELO:', celoBalance.CELO.toString());
console.log('cUSD:', cUsdBalance.toString());
```

## Network Information

| Parameter  | Value     | Details               |
| ---------- | --------- | --------------------- |
| Chain ID   | 42220     | Mainnet               |
| Block Time | 5 seconds | With instant finality |
| Gas Token  | CELO      | Multi-asset fees      |
| Consensus  | PBFT      | Proof of Stake        |

## API Reference

Celo supports the full [Ethereum JSON-RPC API](https://ethereum.org/developers/docs/apis/json-rpc/) plus additional Celo-specific methods for mobile and stable currency features.

## Celo-Specific Features

### Native Stable Currencies

Work with Celo's algorithmic stablecoins:

```javascript
// Stable token addresses on Celo Mainnet
const STABLE_TOKENS = {
  cUSD: '0x765DE816845861e75A25fCA122bb6898B8B1282a',
  cEUR: '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73',
  cREAL: '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787'
};

// Transfer cUSD
async function transferCUSD(to, amount) {
  const cUSD = new ethers.Contract(
    STABLE_TOKENS.cUSD,
    ['function transfer(address to, uint256 amount) returns (bool)'],
    signer
  );

  const tx = await cUSD.transfer(to, ethers.parseUnits(amount, 18));
  await tx.wait();
  return tx.hash;
}
```

### Phone Number Verification

Integrate Celo's identity protocol:

```javascript
// Verify phone number ownership (using Celo SDK)
import { OdisUtils } from '@celo/identity';

async function verifyPhoneNumber(phoneNumber, address) {
  // Get attestation service
  const attestations = await kit.contracts.getAttestations();

  // Request attestations
  const tx = await attestations.request(
    phoneNumber,
    3, // Number of attestations
    address
  );

  await tx.waitReceipt();

  // Complete verification process
  const attestationCode = await getAttestationCode(); // SMS verification
  await attestations.complete(phoneNumber, address, attestationCode);
}
```

### Fee Currency Selection

Pay gas fees with stable tokens:

```javascript
// Configure transaction to pay fees in cUSD
async function sendWithStableFees(to, value) {
  const tx = {
    to,
    value: ethers.parseEther(value),
    feeCurrency: STABLE_TOKENS.cUSD, // Pay fees in cUSD
    gasLimit: 21000,
    gasPrice: await provider.getGasPrice()
  };

  const signedTx = await signer.signTransaction(tx);
  const receipt = await provider.sendTransaction(signedTx);
  return receipt;
}
```

## Common Integration Patterns

### Multi-Currency Wallets

Build wallets supporting multiple Celo assets:

```javascript
class CeloWallet {
  constructor(provider, address) {
    this.provider = provider;
    this.address = address;
  }

  async getBalances() {
    const balances = {};

    // Get CELO balance
    balances.CELO = await this.provider.getBalance(this.address);

    // Get stable token balances
    for (const [symbol, address] of Object.entries(STABLE_TOKENS)) {
      const contract = new ethers.Contract(
        address,
        ['function balanceOf(address) view returns (uint256)'],
        this.provider
      );
      balances[symbol] = await contract.balanceOf(this.address);
    }

    return balances;
  }

  async getUSDValue() {
    const balances = await this.getBalances();
    let totalUSD = 0;

    // cUSD is pegged 1:1
    totalUSD += Number(ethers.formatUnits(balances.cUSD, 18));

    // Get CELO price from oracle
    const celoPrice = await this.getCELOPrice();
    totalUSD += Number(ethers.formatUnits(balances.CELO, 18)) * celoPrice;

    return totalUSD;
  }
}
```

### Mobile Light Client

Optimize for mobile devices:

```javascript
// Ultralight client configuration
class MobileCeloClient {
  constructor(rpcUrl) {
    this.provider = new JsonRpcProvider(rpcUrl, {
      // Optimize for mobile
      timeout: 30000,
      throttleLimit: 1,
      throttleSlotInterval: 1000
    });

    // Cache frequently accessed data
    this.cache = new Map();
  }

  async getBlockHeader(blockNumber) {
    const key = `block_${blockNumber}`;

    if (this.cache.has(key)) {
      return this.cache.get(key);
    }

    // Fetch only essential fields for mobile
    const block = await this.provider.send('eth_getBlockByNumber', [
      ethers.toQuantity(blockNumber),
      false // Don't include transactions
    ]);

    const header = {
      number: block.number,
      hash: block.hash,
      timestamp: block.timestamp,
      gasUsed: block.gasUsed
    };

    this.cache.set(key, header);
    return header;
  }
}
```

### Validator Operations

Interact with Celo's proof-of-stake system:

```javascript
// Stake CELO with validators
async function stakeCELO(validatorAddress, amount) {
  const election = await kit.contracts.getElection();
  const lockedGold = await kit.contracts.getLockedGold();

  // Lock CELO first
  await lockedGold.lock().sendAndWaitForReceipt({
    value: amount
  });

  // Vote for validator
  await election.vote(validatorAddress, amount)
    .sendAndWaitForReceipt();

  console.log(`Staked ${amount} CELO with validator ${validatorAddress}`);
}

// Get validator rewards
async function getRewards(address) {
  const election = await kit.contracts.getElection();
  const rewards = await election.getVoterRewards(address);
  return rewards;
}
```

## Performance Optimization

### 1. **Batch Operations**

Minimize RPC calls with multicall:

```javascript
import { Multicall } from '@celo/contractkit';

async function batchTokenBalances(addresses) {
  const multicall = new Multicall(kit);

  const calls = addresses.flatMap(addr =>
    Object.entries(STABLE_TOKENS).map(([symbol, token]) => ({
      target: token,
      callData: encodeBalanceOf(addr),
      symbol,
      address: addr
    }))
  );

  const results = await multicall.aggregate(calls);
  return parseResults(results);
}
```

### 2. **Archive Node Access**

Leverage Dwellir's archive nodes for historical data:

```javascript
// Query historical stable token prices
async function getHistoricalPrice(blockNumber) {
  const oracle = new ethers.Contract(
    ORACLE_ADDRESS,
    ['function getExchangeRate(address) view returns (uint256, uint256)'],
    provider
  );

  // Use archive node to query past state
  const [numerator, denominator] = await oracle.getExchangeRate(
    STABLE_TOKENS.cUSD,
    { blockTag: blockNumber }
  );

  return numerator / denominator;
}
```

### 3. **Event Indexing**

Efficiently sync events with filters:

```javascript
async function syncTransfers(fromBlock, toBlock) {
  const filter = {
    address: STABLE_TOKENS.cUSD,
    topics: [ethers.id('Transfer(address,address,uint256)')],
    fromBlock,
    toBlock
  };

  // Process in chunks to avoid timeouts
  const chunkSize = 1000;
  const events = [];

  for (let i = fromBlock; i <= toBlock; i += chunkSize) {
    const chunk = await provider.getLogs({
      ...filter,
      fromBlock: i,
      toBlock: Math.min(i + chunkSize - 1, toBlock)
    });
    events.push(...chunk);
  }

  return events;
}
```

## Developer Resources

### Getting Started Guides

#### **Quick Start Tutorial**

Build your first Celo dApp in 10 minutes:

1. **Setup Development Environment**

```bash
# Install Celo CLI
npm install -g @celo/celocli

# Create new project
npx create-react-app my-celo-dapp
cd my-celo-dapp

# Install Celo dependencies
npm install @celo/contractkit ethers
```

2. **Connect to Celo**

```javascript
// src/celo.js
import { newKit } from '@celo/contractkit';

export const kit = newKit(
  'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);
```

3. **Build UI Components**

```jsx
// src/App.js
import { useState, useEffect } from 'react';
import { kit } from './celo';

function App() {
  const [account, setAccount] = useState('');
  const [balance, setBalance] = useState('0');

  useEffect(() => {
    connectWallet();
  }, []);

  async function connectWallet() {
    // Connect to Celo wallet
    const accounts = await kit.web3.eth.getAccounts();
    setAccount(accounts[0]);

    // Get balance
    const bal = await kit.getTotalBalance(accounts[0]);
    setBalance(bal.CELO.toString());
  }

  return (
    <div>
      <h1>My Celo dApp</h1>
      <p>Account: {account}</p>
      <p>Balance: {balance} CELO</p>
    </div>
  );
}
```

#### **Mobile Integration Guide**

Optimize your dApp for mobile users:

```javascript
// Mobile-optimized provider configuration
const mobileConfig = {
  // Reduce timeout for mobile networks
  timeout: 20000,

  // Enable compression
  headers: {
    'Accept-Encoding': 'gzip, deflate'
  },

  // Retry logic for unstable connections
  retry: {
    retries: 3,
    minTimeout: 1000,
    maxTimeout: 5000
  }
};

// Detect mobile and adjust accordingly
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);

const provider = new JsonRpcProvider(
  'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
  isMobile ? mobileConfig : {}
);
```

### Troubleshooting

#### Common Issues and Solutions

| Issue                               | Description                          | Solution                                                           |
| ----------------------------------- | ------------------------------------ | ------------------------------------------------------------------ |
| "Insufficient fee currency balance" | Not enough of selected fee currency  | Ensure account has sufficient cUSD/cEUR or switch to CELO for fees |
| "Invalid feeCurrency address"       | Fee currency not supported           | Use only approved stable tokens: cUSD, cEUR, cREAL                 |
| "Phone number already verified"     | Number linked to another address     | Use Celo's re-verification process or contact support              |
| "Validator not registered"          | Trying to vote for invalid validator | Check validator status with `election.getValidatorGroups()`        |

### Testing on Alfajores Testnet

Get started with Celo's testnet:

```javascript
// Connect to Alfajores testnet
const testnetProvider = new JsonRpcProvider(
  'https://api-celo-alfajores.n.dwellir.com/YOUR_API_KEY'
);

// Alfajores faucet
// Visit: https://faucet.celo.org

// Testnet stable tokens
const ALFAJORES_TOKENS = {
  cUSD: '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1',
  cEUR: '0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F'
};
```

## Migration Guide

### From Ethereum to Celo

Migrating Ethereum dApps to Celo is straightforward:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');
const tx = {
  to: recipient,
  value: amount,
  gasPrice: await provider.getGasPrice()
};

// After (Celo)
const provider = new JsonRpcProvider(
  'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);
const tx = {
  to: recipient,
  value: amount,
  gasPrice: await provider.getGasPrice(),
  feeCurrency: STABLE_TOKENS.cUSD // Optional: pay fees in cUSD
};

// EVM compatible - contracts work without changes
// Same Web3 libraries and tools
// Note: Different chain ID (42220)
// Note: Additional features: stable tokens, phone verification
// New capability: multi-currency gas payments
```

## Ecosystem & Tools

### DeFi on Celo

- **Ubeswap** - Leading DEX on Celo
- **Moola Market** - Lending and borrowing
- **Mento** - Decentralized stable asset protocol
- **Valora** - Mobile-first Celo wallet

### Developer Tools

- [Celo Composer](https://github.com/celo-org/celo-composer) - Full-stack starter kit
- [Remix IDE](https://remix.ethereum.org) - Deploy contracts to Celo
- [Celo Explorer](https://explorer.celo.org) - Block explorer
- [ContractKit](https://docs.celo.org/developer/contractkit) - Celo SDK

### Community Resources

- [Discord](https://discord.gg/celo) - Developer community
- [Forum](https://forum.celo.org) - Technical discussions
- [GitHub](https://github.com/celo-org) - Open source repositories

### Need Help?

- **Email**: <support@dwellir.com>
- **Celo Docs**: [Celo documentation](https://docs.celo.org)
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Top 7 Celo RPC Providers 2026](https://www.dwellir.com/blog/top-celo-rpc-providers)

***

*Build the future of regenerative finance on Celo with Dwellir's reliable RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Celo RPC Method

# debug_traceBlock - Celo RPC Method

Traces all transactions in a block on Celo by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Celo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Celo
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Celo:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Celo blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/celo/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/celo/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/celo/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/celo/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Celo RPC Method

# debug_traceBlockByHash - Celo RPC Method

Traces all transactions in a block on Celo identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Celo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Celo
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Celo:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Celo:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/celo/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/celo/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/celo/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/celo/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/celo/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Celo RPC Method

# debug_traceBlockByNumber - Celo RPC Method

Traces all transactions in a block on Celo identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Celo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Celo execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Celo:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Celo:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/celo/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/celo/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/celo/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/celo/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Celo RPC Method

# debug_traceCall - Celo RPC Method

Traces a call on Celo without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Celo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Celo
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "data": "0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
        "data": "0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
        "data": "0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x471EcE3750Da237f93B8E339c536989b8978a438',
    data: '0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x471EcE3750Da237f93B8E339c536989b8978a438',
    data: '0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x471EcE3750Da237f93B8E339c536989b8978a438',
    'data': '0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x471EcE3750Da237f93B8E339c536989b8978a438",
        "data": "0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Celo to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Celo:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Celo:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x471EcE3750Da237f93B8E339c536989b8978a438',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/celo/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/celo/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/celo/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/celo/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Celo RPC Method

# debug_traceTransaction - Celo RPC Method

Traces a transaction execution on Celo by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Celo
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/celo/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/celo/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Celo RPC Method

# eth_accounts - Celo RPC Method

Returns a list of addresses owned by the client on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for mobile payment developers, fintech builders, and teams targeting emerging markets in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/celo/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/celo/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Celo RPC Method

# eth_blockNumber - Celo RPC Method

Returns the number of the most recent block on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_blockNumber` is fundamental for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Syncing Applications** - Keep your dApp in sync with the latest Celo blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Celo block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Celo block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Celo block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Celo block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Celo block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Celo:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Celo:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Celo node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/celo/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/celo/eth_syncing) - Check if node is still syncing

---

## eth_call - Celo RPC Method

# eth_call - Celo RPC Method

Executes a new message call immediately without creating a transaction on Celo. Used for reading smart contract state.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_call` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Celo
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x471EcE3750Da237f93B8E339c536989b8978a438';
const walletAddress = '0x471EcE3750Da237f93B8E339c536989b8978a438';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Celo. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x471EcE3750Da237f93B8E339c536989b8978a438';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x471EcE3750Da237f93B8E339c536989b8978a438';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Celo
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Celo

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "data": "0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "data": "0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x471EcE3750Da237f93B8E339c536989b8978a438',
    '0x471EcE3750Da237f93B8E339c536989b8978a438'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    data := common.FromHex("0x70a08231000000000000000000000000471EcE3750Da237f93B8E339c536989b8978a438")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Celo RPC Method

# eth_chainId - Celo RPC Method

Returns the chain ID used for transaction signing on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_chainId` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/celo/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/celo/eth_syncing) - Check sync status

---

## eth_coinbase - Celo RPC Method

# eth_coinbase - Celo RPC Method

Checks the legacy `eth_coinbase` compatibility method on Celo. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for mobile payment developers, fintech builders, and teams targeting emerging markets when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Celo coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Celo coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Celo coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Celo coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Celo coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Celo nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/celo/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/celo/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/celo/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Celo RPC Method

# eth_estimateGas - Celo RPC Method

Estimates the gas necessary to execute a transaction on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Celo
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x471EcE3750Da237f93B8E339c536989b8978a438', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x471EcE3750Da237f93B8E339c536989b8978a438', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Celo.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Celo may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x471EcE3750Da237f93B8E339c536989b8978a438',
  '0x471EcE3750Da237f93B8E339c536989b8978a438',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "to": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x471EcE3750Da237f93B8E339c536989b8978a438', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/celo/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Celo RPC Method

# eth_feeHistory - Celo RPC Method

Returns historical gas fee data on Celo, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Celo without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Celo.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Celo) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/celo/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/celo/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Celo RPC Method

# eth_gasPrice - Celo RPC Method

Returns the current gas price on Celo in wei.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Celo
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Celo. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Celo, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Celo: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Celo supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/celo/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/celo/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Celo RPC Method

# eth_getBalance - Celo RPC Method

Returns the balance of a given address on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getBalance` is fundamental for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Celo
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Celo
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Celo. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Celo`);
  return balance;
}

displayBalance('0x471EcE3750Da237f93B8E339c536989b8978a438');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Celo at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x471EcE3750Da237f93B8E339c536989b8978a438'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Celo')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Celo')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Celo.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x471EcE3750Da237f93B8E339c536989b8978a438';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x471EcE3750Da237f93B8E339c536989b8978a438'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/celo/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/celo/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Celo RPC Method

# eth_getBlockByHash - Celo RPC Method

Returns information about a block by hash on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getBlockByHash` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Celo
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Celo.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Celo.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Celo RPC Method

# eth_getBlockByNumber - Celo RPC Method

Returns information about a block by block number on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getBlockByNumber` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Celo
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Celo with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Celo. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/celo/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/celo/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Celo RPC Method

# eth_getBlockReceipts - Celo RPC Method

Returns all transaction receipts for a block on Celo. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getBlockReceipts` is useful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Celo, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Celo. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x37e4542c2bba6522a2dde06f9b0c584520f113e794a10636a8f00f195c74ec16",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/celo/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/celo/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Celo RPC Method

# eth_getCode - Celo RPC Method

Returns the bytecode at a given address on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getCode` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Celo
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Celo:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Celo:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x471EcE3750Da237f93B8E339c536989b8978a438';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x471EcE3750Da237f93B8E339c536989b8978a438'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/celo/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/celo/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Celo RPC Method

# eth_getFilterChanges - Celo RPC Method

Polls a filter on Celo for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getFilterChanges` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Celo
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x471EcE3750Da237f93B8E339c536989b8978a438',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x471EcE3750Da237f93B8E339c536989b8978a438'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Celo:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/celo/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/celo/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/celo/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/celo/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/celo/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Celo RPC Method

# eth_getFilterLogs - Celo RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Celo. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getFilterLogs` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Celo
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x471EcE3750Da237f93B8E339c536989b8978a438"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x471EcE3750Da237f93B8E339c536989b8978a438',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x471EcE3750Da237f93B8E339c536989b8978a438'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/celo/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/celo/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/celo/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/celo/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Celo RPC Method

# eth_getLogs - Celo RPC Method

Returns an array of all logs matching a given filter object on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Celo for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Celo
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x471EcE3750Da237f93B8E339c536989b8978a438';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x471EcE3750Da237f93B8E339c536989b8978a438';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Celo.

```javascript
const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Celo enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Celo, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x471EcE3750Da237f93B8E339c536989b8978a438',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x471EcE3750Da237f93B8E339c536989b8978a438',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/celo/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/celo/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Celo RPC Method

# eth_getStorageAt - Celo RPC Method

Returns the value from a storage position at a given address on Celo. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getStorageAt` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **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 mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **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": [
    "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "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-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x471EcE3750Da237f93B8E339c536989b8978a438', '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-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x471EcE3750Da237f93B8E339c536989b8978a438';

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-celo-mainnet-archive.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 = '0x471EcE3750Da237f93B8E339c536989b8978a438'
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-celo-mainnet-archive.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-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    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 Celo:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.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-celo-mainnet-archive.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 = '0x471EcE3750Da237f93B8E339c536989b8978a438';
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 Celo:`);
  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/celo/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/celo/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/celo/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Celo RPC Method

# eth_getTransactionByHash - Celo RPC Method

Returns the information about a transaction by transaction hash on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getTransactionByHash` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Celo
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Celo. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Celo. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/celo/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Celo RPC Method

# eth_getTransactionCount - Celo RPC Method

Returns the number of transactions sent from an address on Celo, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getTransactionCount` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Celo
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x471EcE3750Da237f93B8E339c536989b8978a438', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Celo nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x471EcE3750Da237f93B8E339c536989b8978a438';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x471EcE3750Da237f93B8E339c536989b8978a438'
nonce = get_transaction_count(address)
print(f'Celo nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Celo nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Celo:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x471EcE3750Da237f93B8E339c536989b8978a438');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/celo/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/celo/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/celo/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Celo RPC Method

# eth_getTransactionReceipt - Celo RPC Method

Returns the receipt of a transaction by transaction hash on Celo. Receipt is only available for mined transactions.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_getTransactionReceipt` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Celo and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Celo. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Celo, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x69d8e9317be809224e01515be6cf3d0716e92b340a680832c45e5e668ff05abe")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/celo/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/celo/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Celo RPC Method

# eth_hashrate - Celo RPC Method

Returns the legacy `eth_hashrate` compatibility value on Celo. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Celo hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Celo hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Celo hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Celo hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Celo hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/celo/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/celo/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Celo RPC Method

# eth_maxPriorityFeePerGas - Celo RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Celo. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Celo
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Celo priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Celo priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Celo priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Celo:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Celo:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/celo/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/celo/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Celo RPC Method

# eth_mining - Celo RPC Method

Checks the legacy `eth_mining` compatibility method on Celo. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Celo mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Celo mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Celo mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Celo mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Celo mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/celo/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/celo/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Celo RPC Method

# eth_newBlockFilter - Celo RPC Method

Creates a filter on Celo that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_newBlockFilter` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Block Monitoring** - Detect new blocks on Celo as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Celo:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/celo/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/celo/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/celo/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Celo RPC Method

# eth_newFilter - Celo RPC Method

Creates a filter object on Celo based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_newFilter` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Event Monitoring** - Subscribe to specific contract events on Celo such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x471EcE3750Da237f93B8E339c536989b8978a438",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x471EcE3750Da237f93B8E339c536989b8978a438",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x471EcE3750Da237f93B8E339c536989b8978a438',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x471EcE3750Da237f93B8E339c536989b8978a438',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Celo:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x471EcE3750Da237f93B8E339c536989b8978a438',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/celo/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/celo/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/celo/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/celo/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/celo/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Celo RPC Method

# eth_newPendingTransactionFilter - Celo RPC Method

Creates a filter on Celo that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Mempool Monitoring** - Observe unconfirmed transactions on Celo to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Celo...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Celo:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/celo/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/celo/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/celo/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Celo RPC Method

# eth_protocolVersion - Celo RPC Method

Returns the current Ethereum protocol version used by the Celo node.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_protocolVersion` is useful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Celo protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Celo protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Celo protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Celo protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Celo protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Celo nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/celo/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/celo/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/celo/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Celo RPC Method

# eth_sendRawTransaction - Celo RPC Method

Submits a pre-signed transaction for broadcast to Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Celo
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x471EcE3750Da237f93B8E339c536989b8978a438', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Celo mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/celo/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x471EcE3750Da237f93B8E339c536989b8978a438")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/celo/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/celo/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Celo RPC Method

# eth_sendTransaction - Celo RPC Method

Creates and sends a new transaction from an unlocked account on Celo. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for mobile payment developers, fintech builders, and teams targeting emerging markets in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Celo tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Celo tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Celo tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Celo tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Celo tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Celo dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/celo/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Celo RPC Method

# eth_signTransaction - Celo RPC Method

Signs a transaction with the private key of the specified account on Celo without submitting it to the network.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for mobile payment developers, fintech builders, and teams targeting emerging markets in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Celo tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Celo tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Celo tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Celo:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/celo/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/celo/eth_accounts) - List accounts available for signing

---

## eth_syncing - Celo RPC Method

# eth_syncing - Celo RPC Method

Returns the sync status of your Celo node - either `false` when fully synced, or an object describing the sync progress.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_syncing` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Celo node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Celo node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Celo node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/celo/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/celo/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/celo/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Celo RPC Method

# eth_uninstallFilter - Celo RPC Method

Removes a filter on Celo that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`eth_uninstallFilter` is important for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/celo/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/celo/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/celo/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/celo/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/celo/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Celo RPC Method

# net_listening - Celo RPC Method

Checks whether the connected Celo client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`net_listening` is useful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Celo node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Celo node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Celo node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/celo/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/celo/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/celo/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/celo/web3_clientVersion) - Get node client info

---

## net_peerCount - Celo RPC Method

# net_peerCount - Celo RPC Method

Returns the number of peers currently connected to your Celo node.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`net_peerCount` is important for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Celo deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Celo peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Celo peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Celo peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Celo nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/celo/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/celo/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/celo/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/celo/web3_clientVersion) - Get node client info

---

## net_version - Celo RPC Method

# net_version - Celo RPC Method

Returns the current network ID on Celo as a decimal string. The network ID identifies which network the node is connected to.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`net_version` is essential for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Endpoint Identification** - Confirm your application is connected to the expected Celo network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Celo network ID:', networkId);

// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Celo network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Celo network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/celo/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/celo/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/celo/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/celo/eth_syncing) - Check node sync progress

---

## rpc_modules - Celo RPC Method

# rpc_modules - Celo RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Celo endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`rpc_modules` is useful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/celo/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/celo/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Celo RPC Method

# txpool_content - Celo RPC Method

Returns the full pending and queued transaction pool for the connected Celo endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`txpool_content` is useful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/celo/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/celo/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/celo/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Celo RPC Method

# txpool_status - Celo RPC Method

Returns transaction pool counters for the connected Celo endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`txpool_status` is valuable for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/celo/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/celo/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/celo/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Celo RPC Method

# web3_clientVersion - Celo RPC Method

Returns the current client software version string for your Celo node, including the client name, version number, OS, and runtime.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

`web3_clientVersion` is valuable for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Celo client:', clientVersion);

// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Celo client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Celo client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/celo/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/celo/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/celo/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/celo/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Celo RPC Method

# web3_sha3 - Celo RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Celo.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/celo/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/celo/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/celo/web3_clientVersion) - Get node client version

---

## Centrifuge RPC Documentation

# Centrifuge RPC Documentation

## Centrifuge RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Centrifuge supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Overview

Centrifuge is the leading Real-World Asset (RWA) protocol and Polkadot parachain, providing infrastructure for tokenizing, managing, and investing in real-world financial assets. Built on the Substrate framework, Centrifuge bridges traditional finance with DeFi, enabling businesses to access instant, bankless liquidity through tokenized credit, real estate, treasuries, and other real-world assets.

This documentation provides comprehensive coverage of Centrifuge's JSON-RPC API methods, enabling developers to interact with Centrifuge nodes for building applications, wallets, explorers, and other blockchain tools.

## Network Information

### Mainnet (Centrifuge)

| Parameter      | Value                                                              | Details |
| -------------- | ------------------------------------------------------------------ | ------- |
| Parachain ID   | 2031                                                               |         |
| Native Token   | CFG                                                                |         |
| Token Decimals | 18                                                                 |         |
| SS58 Prefix    | 36                                                                 |         |
| Consensus      | Nominated Proof-of-Stake (NPoS) via Polkadot                       |         |
| Framework      | Substrate                                                          |         |
| Genesis Hash   | 0xb3db41421702df9a7fcac62b53ffeac85f7853cc4e689e0b93aeb3db18c09d82 |         |

## Connection Endpoints

### HTTPS Endpoint

```
https://api-centrifuge.n.dwellir.com/{YOUR_API_KEY}
```

### WebSocket Endpoint

```
wss://api-centrifuge.n.dwellir.com/{YOUR_API_KEY}
```

## Authentication

Authentication is done via the URL path. Replace `{YOUR_API_KEY}` with your actual API key obtained from [dwellir.com](https://www.dwellir.com).

## API Categories

Centrifuge's RPC API is organized into the following method categories:

### Core APIs

#### Author Methods

Submit and manage extrinsics (transactions) on the network.

#### Chain Methods

Query blockchain data including blocks, headers, and finalized state.

#### State Methods

Access runtime storage, metadata, and proof generation.

#### System Methods

Node information, health checks, and network properties.

### Specialized APIs

#### BEEFY Methods

Bridge Efficiency Enabling Finality Yielder protocol operations.

#### Grandpa Methods

GRANDPA finality gadget operations and proofs.

#### Child State Methods

Manage child storage tries for contracts and parachains.

#### Sync State Methods

Monitor and manage node synchronization state.

## Quick Start Examples

### Get Latest Block

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_getBlock',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Latest block:', data.result);
```

### Submit Transaction

```python
import requests
import json

url = "https://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
headers = {
    "Content-Type": "application/json"
}

# Properly formatted and signed extrinsic
extrinsic = "0x..."

payload = {
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": [extrinsic],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
tx_hash = response.json()["result"]
print(f"Transaction hash: {tx_hash}")
```

### Subscribe to New Blocks (WebSocket)

```javascript
const WebSocket = require('ws');

const ws = new WebSocket('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_subscribeNewHeads',
    params: [],
    id: 1
  }));
});

ws.on('message', (data) => {
  const response = JSON.parse(data);
  if (response.params?.result) {
    console.log('New block:', response.params.result);
  }
});
```

## Error Handling

Centrifuge RPC errors follow the JSON-RPC 2.0 error format:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "Expected hex-encoded hash"
  },
  "id": 1
}
```

### Common Error Codes

| Code   | Message          | Description               |
| ------ | ---------------- | ------------------------- |
| -32700 | Parse error      | Invalid JSON              |
| -32600 | Invalid request  | Missing required fields   |
| -32601 | Method not found | Unknown RPC method        |
| -32602 | Invalid params   | Invalid method parameters |
| -32603 | Internal error   | Node processing error     |
| -32000 | Server error     | Custom server errors      |

## Best Practices

### 1. Connection Management

- Use WebSocket connections for subscriptions and real-time updates
- Implement reconnection logic for WebSocket disconnections
- Use HTTPS for single queries and transactions

### 2. Error Handling

- Always check for error responses before processing results
- Implement retry logic with exponential backoff
- Log errors for debugging and monitoring

### 3. Performance Optimization

- Batch multiple queries when possible
- Cache frequently accessed data like metadata
- Use specific block hashes for deterministic queries

### 4. Security

- Never expose API keys in client-side code
- Validate all input data before submission
- Use secure storage for private keys

## SDK Support

### Official Libraries

- **@polkadot/api** - JavaScript/TypeScript SDK (compatible with Centrifuge)
- **py-substrate-interface** - Python SDK
- **subxt** - Rust SDK
- **go-substrate-rpc-client** - Go SDK

### Integration Example

```javascript
// Using @polkadot/api
const { ApiPromise, WsProvider } = require('@polkadot/api');

async function connect() {
  const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');

  const api = await ApiPromise.create({ provider });

  // Query chain data
  const chain = await api.rpc.system.chain();
  console.log(`Connected to ${chain}`);

  // Get account balance
  const account = 'YOUR_ADDRESS';
  const { data: balance } = await api.query.system.account(account);
  console.log(`Balance: ${balance.free.toString()}`);

  return api;
}
```

## Centrifuge Features

### Real-World Asset Tokenization

Centrifuge is the leading protocol for tokenizing real-world assets, with $270 million in active loans and nearly $500 million in total financed assets. The platform enables:

- **Private Credit** - Tokenization of private credit and lending markets
- **Real Estate** - Property-backed tokenized assets
- **Treasuries** - Government bond tokenization
- **Invoice Financing** - SME invoice and receivables tokenization

### DeFi Integration

Centrifuge bridges traditional finance with DeFi through:

- **Multichain Support** - Integration across Polkadot, Ethereum, and other chains via Wormhole
- **Liquidity Pools** - Tinlake protocol for asset-backed lending pools
- **Institutional Grade** - Compliance-ready infrastructure for regulated assets

### CFG Token

The CFG token serves multiple purposes:

- **Governance** - Community-driven protocol upgrades and parameter changes
- **Staking** - Network security through Polkadot's NPoS
- **Utility** - Access to protocol features and services

### Polkadot Integration

As a Polkadot parachain, Centrifuge benefits from:

- **Shared Security** - Protected by Polkadot's validator network
- **Cross-Chain Interoperability** - Seamless communication with other parachains
- **Scalability** - Leveraging Polkadot's multi-chain architecture

## Additional Resources

- [Centrifuge Website](https://centrifuge.io/)
- [Centrifuge Documentation](https://docs.centrifuge.io/)
- [Centrifuge GitHub](https://github.com/centrifuge)
- [Centrifuge Explorer](https://centrifuge.subscan.io/)
- [Polkadot Parachains Info](https://parachains.info/details/centrifuge)
- [Substrate Documentation](https://docs.substrate.io/)

## Support

For additional support or questions:

- Email: <support@dwellir.com>
- Documentation: [dwellir.com/docs](https://www.dwellir.com/docs)

***

## Method Categories

Select a category below to explore detailed method documentation:

---

## author_pendingExtrinsics - Centrifuge RPC Method

# author_pendingExtrinsics - Centrifuge RPC Method

Returns all pending extrinsics currently in the transaction pool on Centrifuge. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`author_pendingExtrinsics` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Centrifuge
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Centrifuge transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/centrifuge/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/centrifuge/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Centrifuge RPC Method

# author_rotateKeys - Centrifuge RPC Method

Generate a new set of session keys on Centrifuge. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`author_rotateKeys` is critical for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Validator Setup** - Generate initial session keys when setting up a new validator on tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Centrifuge:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/centrifuge/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Centrifuge RPC Method

# author_submitAndWatchExtrinsic - Centrifuge RPC Method

Submits a signed extrinsic to Centrifuge and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Centrifuge
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/centrifuge/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/centrifuge/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Centrifuge RPC Method

# author_submitExtrinsic - Centrifuge RPC Method

Submits a fully signed extrinsic to Centrifuge for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`author_submitExtrinsic` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Token Transfers** -- Send native tokens or assets between accounts on Centrifuge
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/centrifuge/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/centrifuge/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Centrifuge RPC Method

# beefy_getFinalizedHead - Centrifuge RPC Method

Returns the block hash of the latest BEEFY-finalized block on Centrifuge. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`beefy_getFinalizedHead` is important for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/centrifuge/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Centrifuge RPC Method

# chain_getBlock - Centrifuge RPC Method

Retrieves complete block information from Centrifuge, including the block header, extrinsics, and justifications.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/centrifuge/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/centrifuge/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Centrifuge RPC Method

# chain_getBlockHash - Centrifuge RPC Method

Returns the block hash for a given block number on Centrifuge. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`chain_getBlockHash` is fundamental for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Centrifuge
- **Block Navigation** - Navigate the blockchain history for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Centrifuge
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Centrifuge for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Centrifuge state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Centrifuge network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/centrifuge/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Centrifuge RPC Method

# chain_getFinalizedHead - Centrifuge RPC Method

Returns the hash of the last finalized block on Centrifuge. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`chain_getFinalizedHead` is critical for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Centrifuge
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Centrifuge:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/centrifuge/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/centrifuge/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Centrifuge RPC Method

# chain_getHeader - Centrifuge RPC Method

Returns the block header for a given hash on Centrifuge. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`chain_getHeader` is ideal for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Centrifuge
- **Chain Synchronization** - Track block production and monitor chain progress for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Centrifuge:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Centrifuge chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Centrifuge block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/centrifuge/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Centrifuge RPC Method

# chain_subscribeFinalizedHeads - Centrifuge RPC Method

Subscribe to receive notifications when blocks are finalized on Centrifuge. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Exchange Deposits** - Only credit funds after finalization for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Centrifuge:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/centrifuge/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Centrifuge RPC Method

# chain_subscribeNewHeads - Centrifuge RPC Method

Subscribe to receive notifications when new block headers are produced on Centrifuge. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`chain_subscribeNewHeads` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Block Monitoring** - Track new blocks in real time on Centrifuge for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Centrifuge as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Centrifuge:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/centrifuge/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/centrifuge/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## eth_accounts - List available accounts

# eth_accounts - List available accounts

List available accounts on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_accounts",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_blockNumber - Get Latest Block Number

# eth_blockNumber - Get Latest Block Number

Returns the number of the most recent block on Centrifuge Mainnet.

## When to Use This Method

`eth_blockNumber` is fundamental for:

- **Syncing Applications** - Keep your dApp in sync with the latest blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): **Type**: Hexadecimal string **Format**: `0x` prefixed **Example**: `0x5bad55` (6008149 in decimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5bad55"
}
```

## Error Responses

### Error 1

- Code: `-32603`
- Description: Internal error

### Error 2

- Code: `-32005`
- Description: Rate limit exceeded

### Error 3

- Code: `-32000`
- Description: Execution reverted

## Implementation Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch API
const getBlockNumber = async () => {
  const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_blockNumber',
      params: [],
      id: 1
    })
  });
  
  const data = await response.json();
  const blockNumber = parseInt(data.result, 16);
  console.log('Current block:', blockNumber);
  return blockNumber;
};

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Current block:', blockNumber);
```

```python
import requests
import json

def get_block_number():
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
    
    payload = {
        "jsonrpc": "2.0",
        "method": "eth_blockNumber",
        "params": [],
        "id": 1
    }
    
    response = requests.post(url, json=payload)
    data = response.json()
    
    # Convert hex to decimal
    block_number = int(data['result'], 16)
    print(f"Current block: {block_number}")
    return block_number

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'))
block_number = w3.eth.block_number
print(f"Current block: {block_number}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }
    
    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Current block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations:

```javascript
async function getConfirmations(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;
  
  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(txHash, confirmations = 6) {
  let currentConfirmations = 0;
  
  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000)); // Check every 2 seconds
  }
  
  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks:

```javascript
async function getRecentEvents(contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;
  
  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);
  
  return events;
}
```

### 3. Node Health Monitoring

Check if your node is synced:

```javascript
async function checkNodeHealth() {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);
    
    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;
    
    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }
    
    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) { // 2 second cache
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }
  
  async get(provider) {
    const now = Date.now();
    
    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }
    
    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }
  
  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

---

## eth_call - Execute Smart Contract Calls

# eth_call - Execute Smart Contract Calls

**Alchemy** = $11.70 per million `eth_call` requests\
**Quicknode** = $12.40 per million `eth_call` requests\
**Dwellir** = $2 per million `eth_call` requests

Quicknode is **6X more expensive** for `eth_call`s!

[Switch to Dwellir today](https://dashboard.dwellir.com/register)

Executes a new message call immediately without creating a transaction on the blockchain. Used for reading smart contract state.

## When to Use This Method

`eth_call` is essential for:

- **Reading Contract State** - Query view/pure functions
- **Simulating Transactions** - Test execution without gas costs
- **DeFi Integrations** - Check prices, balances, allowances
- **Complex Queries** - Execute multi-step contract logic

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Common Use Cases

### 1. DeFi Price Queries

```javascript
// Uniswap V3 Pool Price Query
async function getPoolPrice(poolAddress) {
  const poolABI = [
    "function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)",
    "function token0() view returns (address)",
    "function token1() view returns (address)"
  ];
  
  const pool = new Contract(poolAddress, poolABI, provider);
  
  const [slot0, token0, token1] = await Promise.all([
    pool.slot0(),
    pool.token0(),
    pool.token1()
  ]);
  
  // Calculate price from sqrtPriceX96
  const sqrtPriceX96 = slot0.sqrtPriceX96;
  const price = (Number(sqrtPriceX96) / (2 ** 96)) ** 2;
  
  return {
    token0: token0,
    token1: token1,
    price: price,
    tick: slot0.tick
  };
}
```

### 2. Multi-Contract Queries

```javascript
// Batch multiple contract calls
async function multicall(calls) {
  const multicallABI = [
    "function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)"
  ];
  
  const multicallAddress = "0xcA11bde05977b3631167028862bE2a173976CA11"; // Centrifuge Multicall3
  const multicall = new Contract(multicallAddress, multicallABI, provider);
  
  const results = await multicall.aggregate(calls);
  return results.returnData;
}
```

### 3. Access Control Checks

```javascript
// Check permissions before transaction
async function checkPermissions(contractAddress, userAddress, role) {
  const accessControlABI = [
    "function hasRole(bytes32 role, address account) view returns (bool)",
    "function getRoleAdmin(bytes32 role) view returns (bytes32)"
  ];
  
  const contract = new Contract(contractAddress, accessControlABI, provider);
  const hasRole = await contract.hasRole(role, userAddress);
  
  return hasRole;
}
```

---

## eth_chainId - Get chain ID

# eth_chainId - Get chain ID

Get chain ID on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_chainId",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_chainId',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_coinbase - Get coinbase address

# eth_coinbase - Get coinbase address

Get coinbase address on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_coinbase",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_estimateGas - Estimate Transaction Gas

# eth_estimateGas - Estimate Transaction Gas

Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain.

## When to Use This Method

`eth_estimateGas` is crucial for:

- **Transaction Preparation** - Calculate gas limits before sending
- **Cost Estimation** - Preview transaction fees for users
- **Gas Optimization** - Find optimal gas usage for complex operations
- **Error Prevention** - Detect failures before broadcasting

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Common Use Cases

### 1. Pre-Transaction Validation

```javascript
// Validate transaction before sending
async function validateTransaction(from, to, value, data) {
  try {
    const gasEstimate = await provider.estimateGas({
      from: from,
      to: to,
      value: value,
      data: data
    });
    
    // Check if account has enough balance
    const balance = await provider.getBalance(from);
    const feeData = await provider.getFeeData();
    const maxCost = value + (gasEstimate * feeData.maxFeePerGas);
    
    if (balance < maxCost) {
      return {
        valid: false,
        reason: 'Insufficient balance',
        required: ethers.formatEther(maxCost),
        available: ethers.formatEther(balance)
      };
    }
    
    return {
      valid: true,
      gasLimit: gasEstimate.toString(),
      estimatedFee: ethers.formatEther(gasEstimate * feeData.gasPrice)
    };
  } catch (error) {
    return {
      valid: false,
      reason: error.message
    };
  }
}
```

### 2. Dynamic Gas Pricing UI

```javascript
// Real-time gas price updates for UI
class GasPriceMonitor {
  constructor(provider) {
    this.provider = provider;
    this.listeners = [];
  }
  
  async getCurrentPrices() {
    const [feeData, block] = await Promise.all([
      this.provider.getFeeData(),
      this.provider.getBlock('latest')
    ]);
    
    return {
      slow: {
        maxFeePerGas: feeData.maxFeePerGas * 90n / 100n,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * 80n / 100n,
        estimatedTime: '2-5 minutes'
      },
      standard: {
        maxFeePerGas: feeData.maxFeePerGas,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
        estimatedTime: '15-30 seconds'
      },
      fast: {
        maxFeePerGas: feeData.maxFeePerGas * 120n / 100n,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * 150n / 100n,
        estimatedTime: '5-15 seconds'
      },
      baseFee: block.baseFeePerGas
    };
  }
  
  async estimateForTransaction(tx, speed = 'standard') {
    const prices = await this.getCurrentPrices();
    const gasEstimate = await this.provider.estimateGas(tx);
    const settings = prices[speed];
    
    return {
      gasLimit: gasEstimate,
      ...settings,
      estimatedCost: ethers.formatEther(gasEstimate * settings.maxFeePerGas),
      maxCost: ethers.formatEther(gasEstimate * settings.maxFeePerGas)
    };
  }
}
```

### 3. Batch Operation Optimization

```javascript
// Optimize gas for batch operations
async function optimizeBatchTransactions(transactions) {
  const estimates = [];
  let totalGas = 0n;
  
  // Estimate individually
  for (const tx of transactions) {
    const estimate = await provider.estimateGas(tx);
    estimates.push(estimate);
    totalGas += estimate;
  }
  
  // Check if multicall is more efficient
  const multicallEstimate = await estimateMulticall(transactions);
  
  if (multicallEstimate < totalGas * 90n / 100n) {
    return {
      method: 'multicall',
      gasLimit: multicallEstimate,
      savings: ethers.formatUnits(totalGas - multicallEstimate, 'gwei')
    };
  }
  
  return {
    method: 'individual',
    gasLimits: estimates,
    totalGas: totalGas
  };
}
```

---

## eth_feeHistory - Get historical gas prices

# eth_feeHistory - Get historical gas prices

Returns historical gas information for the Centrifuge network. This method is useful for gas price estimation and understanding network congestion patterns over time.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_feeHistory",
        "params": ["0x4", "latest", [25, 50, 75]],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `oldestBlock`: `QUANTITY` - Lowest block number returned `baseFeePerGas`: `Array` - Array of base fees per gas for each block `gasUsedRatio`: `Array` - Array of gas used ratios for each block (0.0 to 1.0) `reward`: `Array` - Array of arrays containing priority fees at requested percentiles

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1a2b3c4",
    "baseFeePerGas": [
      "0x3b9aca00",
      "0x3b9aca00",
      "0x3b9aca00",
      "0x3b9aca00"
    ],
    "gasUsedRatio": [0.5, 0.6, 0.4, 0.7],
    "reward": [
      ["0x77359400", "0x77359400", "0x77359400"],
      ["0x77359400", "0x77359400", "0x77359400"],
      ["0x77359400", "0x77359400", "0x77359400"]
    ]
  }
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x4", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0x4', 'latest', [25, 50, 75]],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_gasPrice - Get Current Gas Price

# eth_gasPrice - Get Current Gas Price

Returns the current gas price in wei. This represents the median gas price from recent blocks on Centrifuge Mainnet.

## When to Use This Method

`eth_gasPrice` is essential for:

- **Transaction Pricing** - Set appropriate gas prices for transactions
- **Fee Estimation** - Calculate transaction costs for users
- **Gas Strategy** - Optimize transaction speed vs cost
- **Market Monitoring** - Track network congestion levels

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Common Use Cases

### 1. Dynamic Fee Adjustment

```javascript
// Dynamically adjust fees based on network conditions
async function getOptimalGasPrice(urgency = 'standard') {
  const gasPrice = await provider.getGasPrice();
  const block = await provider.getBlock('latest');
  const baseFee = block.baseFeePerGas;
  
  const multipliers = {
    low: 0.9,
    standard: 1.0,
    high: 1.2,
    urgent: 1.5
  };
  
  const multiplier = multipliers[urgency] || 1.0;
  const adjustedPrice = gasPrice * BigInt(Math.floor(multiplier * 100)) / 100n;
  
  // For EIP-1559 transactions
  const maxPriorityFee = adjustedPrice - baseFee;
  const maxFeePerGas = baseFee * 2n + maxPriorityFee;
  
  return {
    legacy: {
      gasPrice: adjustedPrice,
      formatted: formatGwei(adjustedPrice) + ' gwei'
    },
    eip1559: {
      maxFeePerGas: maxFeePerGas,
      maxPriorityFeePerGas: maxPriorityFee,
      formatted: {
        maxFee: formatGwei(maxFeePerGas) + ' gwei',
        priorityFee: formatGwei(maxPriorityFee) + ' gwei'
      }
    },
    estimatedConfirmationBlocks: urgency === 'urgent' ? 1 : urgency === 'high' ? 2 : 3
  };
}
```

### 2. Gas Price Oracle

```javascript
// Create a gas price oracle with caching
class GasPriceOracle {
  constructor(provider, cacheTime = 5000) {
    this.provider = provider;
    this.cacheTime = cacheTime;
    this.cache = null;
    this.lastFetch = 0;
  }
  
  async getPrice() {
    const now = Date.now();
    
    if (this.cache && (now - this.lastFetch) < this.cacheTime) {
      return this.cache;
    }
    
    const gasPrice = await this.provider.getGasPrice();
    
    this.cache = {
      wei: gasPrice,
      gwei: formatGwei(gasPrice),
      timestamp: now
    };
    this.lastFetch = now;
    
    return this.cache;
  }
  
  async getPriceWithRecommendations() {
    const price = await this.getPrice();
    const gweiPrice = parseFloat(price.gwei);
    
    return {
      ...price,
      recommendations: {
        sendNow: gweiPrice < 1,
        waitSuggested: gweiPrice > 5,
        congestionLevel: gweiPrice < 0.5 ? 'low' : gweiPrice < 2 ? 'normal' : 'high'
      }
    };
  }
}
```

### 3. Transaction Cost Calculator

```javascript
// Calculate and display transaction costs
async function calculateDetailedCosts(gasLimit) {
  const gasPrice = await provider.getGasPrice();
  const ethPrice = 3000; // Would fetch from price feed
  
  const costs = {
    slow: gasPrice * 90n / 100n,
    standard: gasPrice,
    fast: gasPrice * 120n / 100n
  };
  
  const results = {};
  
  for (const [speed, price] of Object.entries(costs)) {
    const totalWei = price * BigInt(gasLimit);
    const totalETH = Number(formatEther(totalWei));
    
    results[speed] = {
      gasPrice: formatGwei(price) + ' gwei',
      totalETH: totalETH.toFixed(6) + ' ETH',
      totalUSD: '$' + (totalETH * ethPrice).toFixed(2),
      percentOfTransfer: gasLimit === 21000 ? 'N/A' : 
        ((Number(totalWei) / Number(parseEther('1'))) * 100).toFixed(3) + '%'
    };
  }
  
  return results;
}
```

---

## eth_getBalance - Query Account Balance

# eth_getBalance - Query Account Balance

Returns the ETH balance of a given address on Centrifuge Mainnet.

## When to Use This Method

`eth_getBalance` is essential for:

- **Wallet Applications** - Display user balances
- **Transaction Validation** - Check if account has sufficient funds
- **DeFi Applications** - Monitor collateral and liquidity
- **Account Monitoring** - Track balance changes over time

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): **Type**: Hexadecimal string **Unit**: Wei (1 ETH = 10^18 wei) **Format**: `0x` prefixed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Error Responses

### Error 1

- Code: `-32602`
- Description: Invalid address format

### Error 2

- Code: `-32602`
- Description: Invalid block parameter

### Error 3

- Code: `-32000`
- Description: Account not found

## Implementation Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using ethers.js
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY');

async function getBalance(address) {
  // Get balance in wei
  const balanceWei = await provider.getBalance(address);
  
  // Convert to ETH
  const balanceEth = formatEther(balanceWei);
  
  console.log(`Balance: ${balanceEth} ETH`);
  return balanceEth;
}

// Check multiple balances
async function getMultipleBalances(addresses) {
  const balances = await Promise.all(
    addresses.map(async (addr) => {
      const balance = await provider.getBalance(addr);
      return {
        address: addr,
        balance: formatEther(balance)
      };
    })
  );
  return balances;
}
```

```python
from web3 import Web3

# Connect to Ethereum
w3 = Web3(Web3.HTTPProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'))

def get_balance(address):
    # Get balance in wei
    balance_wei = w3.eth.get_balance(address)
    
    # Convert to ETH
    balance_eth = w3.from_wei(balance_wei, 'ether')
    
    print(f"Balance: {balance_eth} ETH")
    return balance_eth

# Get balance at specific block
def get_historical_balance(address, block_number):
    balance_wei = w3.eth.get_balance(address, block_identifier=block_number)
    return w3.from_wei(balance_wei, 'ether')

# Monitor balance changes
def monitor_balance(address, interval=2):
    import time
    last_balance = 0
    
    while True:
        current_balance = w3.eth.get_balance(address)
        if current_balance != last_balance:
            change = current_balance - last_balance
            print(f"Balance changed: {w3.from_wei(change, 'ether')} ETH")
            last_balance = current_balance
        time.sleep(interval)
```

```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-centrifuge.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }
    
    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    
    // Get balance at latest block
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    
    // Convert wei to ETH
    ethValue := new(big.Float).Quo(
        new(big.Float).SetInt(balance),
        big.NewFloat(1e18),
    )
    
    fmt.Printf("Balance: %f ETH\n", ethValue)
}
```

## Common Use Cases

### 1. Wallet Balance Display

Display formatted balance with USD value:

```javascript
async function displayWalletBalance(address) {
  const provider = new JsonRpcProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
  
  // Get ETH balance
  const balance = await provider.getBalance(address);
  const ethBalance = formatEther(balance);
  
  // Get ETH price (from your price oracle)
  const ethPrice = await getEthPrice(); // Implement this
  const usdValue = parseFloat(ethBalance) * ethPrice;
  
  return {
    eth: ethBalance,
    usd: usdValue.toFixed(2),
    formatted: `${ethBalance} ETH ($${usdValue.toFixed(2)})`
  };
}
```

### 2. Transaction Pre-validation

Check if account has enough balance for transaction:

```javascript
async function canAffordTransaction(from, to, value, gasLimit, maxFeePerGas) {
  const balance = await provider.getBalance(from);
  
  // Calculate total cost
  const valueBigInt = BigInt(value);
  const gasCost = BigInt(gasLimit) * BigInt(maxFeePerGas);
  const totalCost = valueBigInt + gasCost;
  
  if (balance < totalCost) {
    const shortage = formatEther(totalCost - balance);
    throw new Error(`Insufficient balance. Need ${shortage} more ETH`);
  }
  
  return true;
}
```

### 3. Balance Change Detection

Monitor account for balance changes:

```javascript
class BalanceMonitor {
  constructor(provider, address) {
    this.provider = provider;
    this.address = address;
    this.lastBalance = null;
  }
  
  async start(callback, interval = 2000) {
    setInterval(async () => {
      const currentBalance = await this.provider.getBalance(this.address);
      
      if (this.lastBalance && currentBalance !== this.lastBalance) {
        const change = currentBalance - this.lastBalance;
        callback({
          address: this.address,
          previousBalance: this.lastBalance,
          currentBalance,
          change,
          changeFormatted: formatEther(change)
        });
      }
      
      this.lastBalance = currentBalance;
    }, interval);
  }
}

// Usage
const monitor = new BalanceMonitor(provider, "0x...");
monitor.start((data) => {
  console.log(`Balance changed by ${data.changeFormatted} ETH`);
});
```

### 4. Historical Balance Query

Get balance at specific block:

```javascript
async function getBalanceHistory(address, blocks) {
  const history = [];
  
  for (const blockNumber of blocks) {
    const balance = await provider.getBalance(address, blockNumber);
    const block = await provider.getBlock(blockNumber);
    
    history.push({
      block: blockNumber,
      timestamp: block.timestamp,
      balance: formatEther(balance)
    });
  }
  
  return history;
}

// Get balance every 1000 blocks
async function getBalanceSnapshots(address, count = 10) {
  const currentBlock = await provider.getBlockNumber();
  const blocks = [];
  
  for (let i = 0; i < count; i++) {
    blocks.push(currentBlock - (i * 1000));
  }
  
  return getBalanceHistory(address, blocks);
}
```

## Performance Optimization

### Batch Balance Queries

Query multiple balances efficiently:

```javascript
async function batchGetBalances(addresses) {
  const batch = addresses.map((addr, i) => ({
    jsonrpc: '2.0',
    method: 'eth_getBalance',
    params: [addr, 'latest'],
    id: i
  }));
  
  const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(batch)
  });
  
  const results = await response.json();
  return results.map((r, i) => ({
    address: addresses[i],
    balance: formatEther(BigInt(r.result))
  }));
}
```

### Caching Strategy

Implement smart caching for balance queries:

```javascript
class BalanceCache {
  constructor(ttl = 5000) {
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  getCacheKey(address, block) {
    return `${address}-${block}`;
  }
  
  async getBalance(provider, address, block = 'latest') {
    const key = this.getCacheKey(address, block);
    const cached = this.cache.get(key);
    
    // Return cached if block is not 'latest' (immutable)
    if (cached && block !== 'latest') {
      return cached.balance;
    }
    
    // Check TTL for 'latest' block
    if (cached && block === 'latest') {
      if (Date.now() - cached.timestamp < this.ttl) {
        return cached.balance;
      }
    }
    
    // Fetch fresh balance
    const balance = await provider.getBalance(address, block);
    this.cache.set(key, {
      balance,
      timestamp: Date.now()
    });
    
    return balance;
  }
}
```

---

## eth_getBlockByHash - Get block Info by ha...

# eth_getBlockByHash - Get block Info by ha...

Retrieves comprehensive information about a block on Centrifuge Mainnet by its hash identifier, including header data, transaction lists, and execution metrics.

## Request Parameters

- `blockHash` (`string, required`): The 32-byte block hash (66 characters with 0x prefix)
- `fullTransactionObjects` (`boolean, required`): When `true`, returns complete transaction objects. When `false`, returns only transaction hashes

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_getBlockByHash",
        "params": [
          "0xba6064a55ed3dc3f34185d57dc000a63639302bf17f6eaf61c2f211d25f73a67",
          false
        ],
        "id": 1
      }'
```

## Response Fields

- `number` (`string, required`): Block number in hexadecimal
- `hash` (`string, required`): 32-byte block hash
- `parentHash` (`string, required`): Hash of the parent block
- `nonce` (`string, required`): Proof-of-work nonce (always 0x0000000000000000 on Centrifuge Mainnet)
- `sha3Uncles` (`string, required`): SHA3 hash of uncles data
- `logsBloom` (`string, required`): 256-byte bloom filter for block logs
- `transactionsRoot` (`string, required`): Root hash of the transaction trie
- `stateRoot` (`string, required`): Root hash of the final state trie
- `receiptsRoot` (`string, required`): Root hash of the receipts trie
- `miner` (`string, required`): Address receiving block rewards
- `difficulty` (`string, required`): Block difficulty (always 0x0 on Centrifuge Mainnet)
- `totalDifficulty` (`string, required`): Total chain difficulty up to this block
- `extraData` (`string, required`): Additional block-specific data
- `size` (`string, required`): Block size in bytes (hexadecimal)
- `gasLimit` (`string, required`): Maximum gas allowed in block
- `gasUsed` (`string, required`): Total gas consumed by all transactions
- `timestamp` (`string, required`): Unix timestamp of block creation
- `transactions` (`array, required`): Array of transaction hashes or full transaction objects
- `uncles` (`array, required`): Array of uncle block hashes (always empty on Centrifuge Mainnet)
- `baseFeePerGas` (`string, required`): Base fee per gas unit (EIP-1559)
- `withdrawals` (`array, required`): Validator withdrawals (if applicable)
- `withdrawalsRoot` (`string, required`): Root hash of withdrawals trie

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "baseFeePerGas": "0x2da282a8",
    "difficulty": "0x0",
    "extraData": "0x",
    "gasLimit": "0x1c9c380",
    "gasUsed": "0x3b9aca",
    "hash": "0xba6064a55ed3dc3f34185d57dc000a63639302bf17f6eaf61c2f211d25f73a67",
    "logsBloom": "0x00000000000000000000000000000000...",
    "miner": "0x0000000000000000000000000000000000000000",
    "nonce": "0x0000000000000000",
    "number": "0x5bad55",
    "parentHash": "0xb4fbadf8ea452b139718e2700dc1135cfc81145031c84b7ab27cd99f43ec28ca",
    "receiptsRoot": "0x9b0816dba2e4c1c7b2d38d0c3da6e6bb93c1713a7e986e38f856b6fb725234cf",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "size": "0x21d",
    "stateRoot": "0xddc8b0234248b014296fed29c5c0e9d6e5a6e4a0576ce66970a36c064e3cd96b",
    "timestamp": "0x5e0be0ff",
    "totalDifficulty": "0x0",
    "transactions": [
      "0x5d2dd8b32dc30f347120c5877975c93ccf3e5a5c9ad0c595b0a73c3e00c9e9bb",
      "0x8a91b1b37e0e463c27cb340dc0e2cbc5636cba8d9b3e9a66c2a9e6c3f8c65e82"
    ],
    "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
    "uncles": []
  }
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xba6064a55ed3dc3f34185d57dc000a63639302bf17f6eaf61c2f211d25f73a67",
      false
    ],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getBlockByHash',
    params: [
      '0xba6064a55ed3dc3f34185d57dc000a63639302bf17f6eaf61c2f211d25f73a67',
      false  // Set to true for full transaction objects
    ],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

```python
import requests
import json

url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}

payload = {
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
        "0xba6064a55ed3dc3f34185d57dc000a63639302bf17f6eaf61c2f211d25f73a67",
        False  # Set to True for full transaction objects
    ],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
print(response.json()['result'])
```

---

## eth_getBlockByNumber - Get Block Details

# eth_getBlockByNumber - Get Block Details

Returns information about a block by block number on Centrifuge Mainnet.

## When to Use This Method

`eth_getBlockByNumber` is crucial for:

- **Block Explorers** - Display block information and transactions
- **Chain Analytics** - Analyze block patterns and metrics
- **Transaction Verification** - Confirm transaction inclusion
- **DApp Synchronization** - Process blocks sequentially

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number, null if pending
- `hash` (``DATA`, 32 bytes, required`): Block hash, null if pending
- `parentHash` (``DATA`, 32 bytes, required`): Parent block hash
- `nonce` (``DATA`, 8 bytes, required`): Proof-of-work nonce (always 0 on Ethereum)
- `sha3Uncles` (``DATA`, 32 bytes, required`): SHA3 of uncles (always empty on Ethereum)
- `logsBloom` (``DATA`, 256 bytes, required`): Bloom filter for logs
- `transactionsRoot` (``DATA`, 32 bytes, required`): Root of transaction trie
- `stateRoot` (``DATA`, 32 bytes, required`): Root of final state trie
- `receiptsRoot` (``DATA`, 32 bytes, required`): Root of receipts trie
- `miner` (``DATA`, 20 bytes, required`): Beneficiary address (sequencer on Ethereum)
- `difficulty` (`QUANTITY, required`): Difficulty (always 0 on Ethereum)
- `totalDifficulty` (`QUANTITY, required`): Total difficulty
- `extraData` (`DATA, required`): Extra data field
- `size` (`QUANTITY, required`): Block size in bytes
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed
- `gasUsed` (`QUANTITY, required`): Total gas used by transactions
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `transactions` (`Array, required`): Transaction objects or hashes
- `uncles` (`Array, required`): Uncle hashes (always empty on Ethereum)
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)
- `l1BlockNumber` (`QUANTITY, required`): Corresponding L1 block (Centrifuge specific)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "baseFeePerGas": "0x3e",
    "difficulty": "0x0",
    "extraData": "0x",
    "gasLimit": "0x1c9c380",
    "gasUsed": "0x4f916",
    "hash": "0x1234567890abcdef...",
    "logsBloom": "0x00000000...",
    "miner": "0x0000000000000000000000000000000000000000",
    "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "nonce": "0x0000000000000000",
    "number": "0x86c4dd",
    "parentHash": "0xabcdef1234567890...",
    "receiptsRoot": "0x...",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "size": "0x4d6",
    "stateRoot": "0x...",
    "timestamp": "0x64f1b438",
    "totalDifficulty": "0x0",
    "transactions": [
      "0xhash1...",
      "0xhash2...",
      "0xhash3..."
    ],
    "transactionsRoot": "0x...",
    "uncles": []
  }
}
```

## Error Responses

### Error 1

- Code: `-32602`
- Description: Invalid block number

### Error 2

- Code: `-32000`
- Description: Block not found

### Error 3

- Code: `-32005`
- Description: Rate limit exceeded

## Implementation Examples

cURL
JavaScript
Python
Go

```bash
# Get block with transaction hashes only
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'

# Get block with full transaction details
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["0x86c4dd", true],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY');

// Get latest block with transactions
async function getLatestBlock() {
  const block = await provider.getBlock('latest', true);
  
  console.log('Block Number:', block.number);
  console.log('Block Hash:', block.hash);
  console.log('Timestamp:', new Date(block.timestamp * 1000));
  console.log('Transactions:', block.transactions.length);
  console.log('Gas Used:', block.gasUsed.toString());
  console.log('Centrifuge Fee:', block.baseFeePerGas?.toString());
  
  return block;
}

// Get block range
async function getBlockRange(start, end) {
  const blocks = [];
  
  for (let i = start; i <= end; i++) {
    const block = await provider.getBlock(i);
    blocks.push({
      number: block.number,
      timestamp: block.timestamp,
      transactions: block.transactions.length,
      gasUsed: block.gasUsed.toString()
    });
  }
  
  return blocks;
}

// Analyze block statistics
async function analyzeBlock(blockNumber) {
  const block = await provider.getBlock(blockNumber, true);
  
  const analysis = {
    number: block.number,
    timestamp: new Date(block.timestamp * 1000),
    transactionCount: block.transactions.length,
    gasUsed: block.gasUsed,
    gasLimit: block.gasLimit,
    utilization: (Number(block.gasUsed) / Number(block.gasLimit) * 100).toFixed(2) + '%',
    baseFee: block.baseFeePerGas,
    totalValue: block.transactions.reduce((sum, tx) => sum + BigInt(tx.value || 0), 0n)
  };
  
  return analysis;
}
```

```python
from web3 import Web3
from datetime import datetime

w3 = Web3(Web3.HTTPProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'))

def get_block_details(block_identifier='latest', full_transactions=False):
    """Get block with optional full transaction details"""
    block = w3.eth.get_block(block_identifier, full_transactions)
    
    return {
        'number': block['number'],
        'hash': block['hash'].hex(),
        'timestamp': datetime.fromtimestamp(block['timestamp']),
        'transactions': len(block['transactions']),
        'gas_used': block['gasUsed'],
        'gas_limit': block['gasLimit'],
        'base_fee': block.get('baseFeePerGas', 0)
    }

def analyze_blocks(start_block, num_blocks=10):
    """Analyze multiple blocks for patterns"""
    blocks_data = []
    
    for i in range(num_blocks):
        block_num = start_block + i
        block = w3.eth.get_block(block_num)
        
        blocks_data.append({
            'number': block_num,
            'timestamp': block['timestamp'],
            'tx_count': len(block['transactions']),
            'gas_used': block['gasUsed'],
            'block_time': block['timestamp'] - blocks_data[-1]['timestamp'] 
                        if blocks_data else 0
        })
    
    # Calculate averages
    avg_tx = sum(b['tx_count'] for b in blocks_data) / len(blocks_data)
    avg_gas = sum(b['gas_used'] for b in blocks_data) / len(blocks_data)
    avg_time = sum(b['block_time'] for b in blocks_data[1:]) / (len(blocks_data) - 1)
    
    return {
        'blocks': blocks_data,
        'averages': {
            'transactions_per_block': avg_tx,
            'gas_per_block': avg_gas,
            'block_time': avg_time
        }
    }
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"
    
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }
    
    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Block Number: %s\n", block.Number().String())
    fmt.Printf("Block Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Block Time: %s\n", time.Unix(int64(block.Time()), 0))
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
    fmt.Printf("Gas Used: %d\n", block.GasUsed())
    
    // Get specific block
    blockNumber := big.NewInt(1000000)
    historicalBlock, err := client.BlockByNumber(context.Background(), blockNumber)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Historical Block: %s\n", historicalBlock.Number().String())
}
```

## Common Use Cases

### 1. Block Explorer Display

```javascript
async function formatBlockForExplorer(blockNumber) {
  const block = await provider.getBlock(blockNumber, true);
  
  return {
    number: block.number,
    hash: block.hash,
    timestamp: new Date(block.timestamp * 1000).toISOString(),
    miner: block.miner,
    transactionCount: block.transactions.length,
    gasUsed: `${(Number(block.gasUsed) / 1e6).toFixed(2)}M`,
    gasLimit: `${(Number(block.gasLimit) / 1e6).toFixed(2)}M`,
    utilization: `${(Number(block.gasUsed) / Number(block.gasLimit) * 100).toFixed(2)}%`,
    baseFee: `${Number(block.baseFeePerGas) / 1e9} Gwei`,
    burnt: formatEther(block.gasUsed * block.baseFeePerGas)
  };
}
```

### 2. Transaction Confirmation

```javascript
async function confirmTransaction(txHash, confirmations = 6) {
  const tx = await provider.getTransaction(txHash);
  if (!tx) throw new Error('Transaction not found');
  
  const receipt = await provider.getTransactionReceipt(txHash);
  if (!receipt) {
    console.log('Transaction pending...');
    return false;
  }
  
  const currentBlock = await provider.getBlockNumber();
  const confirmCount = currentBlock - receipt.blockNumber + 1;
  
  if (confirmCount >= confirmations) {
    const block = await provider.getBlock(receipt.blockNumber, true);
    const txInBlock = block.transactions.find(t => t.hash === txHash);
    
    return {
      confirmed: true,
      confirmations: confirmCount,
      block: receipt.blockNumber,
      timestamp: block.timestamp,
      position: txInBlock ? block.transactions.indexOf(txInBlock) : -1
    };
  }
  
  return {
    confirmed: false,
    confirmations: confirmCount,
    needed: confirmations - confirmCount
  };
}
```

### 3. Block Time Analysis

```javascript
async function analyzeBlockTimes(count = 100) {
  const latest = await provider.getBlockNumber();
  const blocks = [];
  
  for (let i = 0; i < count; i++) {
    const block = await provider.getBlock(latest - i);
    blocks.push({
      number: block.number,
      timestamp: block.timestamp
    });
  }
  
  const blockTimes = [];
  for (let i = 1; i < blocks.length; i++) {
    blockTimes.push(blocks[i-1].timestamp - blocks[i].timestamp);
  }
  
  return {
    average: blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length,
    min: Math.min(...blockTimes),
    max: Math.max(...blockTimes),
    blocks: blockTimes
  };
}
```

### 4. Gas Price Tracking

```javascript
async function trackGasPrices(blocks = 10) {
  const latest = await provider.getBlockNumber();
  const gasPrices = [];
  
  for (let i = 0; i < blocks; i++) {
    const block = await provider.getBlock(latest - i, true);
    
    // Calculate effective gas prices from transactions
    const prices = block.transactions
      .filter(tx => tx.gasPrice || tx.maxFeePerGas)
      .map(tx => {
        if (tx.type === 2) { // EIP-1559
          return BigInt(tx.maxFeePerGas) < BigInt(block.baseFeePerGas) + BigInt(tx.maxPriorityFeePerGas)
            ? BigInt(tx.maxFeePerGas)
            : BigInt(block.baseFeePerGas) + BigInt(tx.maxPriorityFeePerGas);
        }
        return BigInt(tx.gasPrice);
      });
    
    if (prices.length > 0) {
      const avgPrice = prices.reduce((a, b) => a + b, 0n) / BigInt(prices.length);
      gasPrices.push({
        block: block.number,
        baseFee: Number(block.baseFeePerGas) / 1e9,
        avgPrice: Number(avgPrice) / 1e9,
        txCount: block.transactions.length
      });
    }
  }
  
  return gasPrices;
}
```

## Performance Optimization

### Parallel Block Fetching

```javascript
async function getBlocksParallel(startBlock, count) {
  const promises = [];
  
  for (let i = 0; i < count; i++) {
    promises.push(provider.getBlock(startBlock + i));
  }
  
  const blocks = await Promise.all(promises);
  return blocks;
}
```

### Block Caching

```javascript
class BlockCache {
  constructor(maxSize = 100) {
    this.cache = new Map();
    this.maxSize = maxSize;
  }
  
  async getBlock(provider, blockNumber, fullTx = false) {
    const key = `${blockNumber}-${fullTx}`;
    
    if (this.cache.has(key)) {
      return this.cache.get(key);
    }
    
    const block = await provider.getBlock(blockNumber, fullTx);
    
    // LRU eviction
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    
    this.cache.set(key, block);
    return block;
  }
}
```

---

## eth_getCode - Get Centrifuge Contract Byt...

# eth_getCode - Get Centrifuge Contract Byt...

Retrieves the compiled bytecode of a smart contract deployed on the Centrifuge network. This method is essential for contract verification, security analysis, and understanding deployed contract functionality on Ethereum's Layer 2 infrastructure.

## Request Parameters

- `address` (`string, required`): The 20-byte address of the contract (0x-prefixed hex string)
- `blockNumber/blockTag` (`string, required`): Block number in hex (e.g., "0x1b4") or block tag: "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "<address>",
    "<blockNumber/blockTag>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded bytecode starting with "0x". Returns "0x" for EOA addresses

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x608060405234801561001057600080fd5b50600436106101735760003560e01c80638da5cb5b116100de578063c87b56dd11610097578063e985e9c511610071578063e985e9c5146104a2578063f2fde38b146104de578063f46a04eb146104fa578063f5298aca1461051657610173565b8063c87b56dd1461044a578063d547741f14610466578063e8a3d4851461048257610173565b80638da5cb5b146103a657806391d14854146103c457806395d89b41146103e0578063a217fddf146103fe578063a22cb4651461041c578063bd85b0391461043857610173565b80632f2ff15d1161013057806336568abe1161010a57806336568abe146103285780634e1273f414610344578063715018a6146103745780638456cb591461037e57610173565b80632f2ff15d146102cc5780633659cfe6146102e85780633f4ba83a1461030457610173565b8062fdd58e1461017857806301ffc9a71461019857806306fdde03146101c85780630e89341c146101e6578063248a9ca3146102065780632eb2c2d614610236575b600080fd5b610182600480360381019061017d9190611c3a565b610532565b60405161018f9190611c89565b60405180910390f35b6101b260048036038101906101ad9190611cfc565b6105fa565b60405161..."
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get bytecode for USDC contract on Ethereum
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Get bytecode for Ethereum's official bridge contract
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getCode',
    params: [
      '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      'latest'
    ],
    id: 1
  })
});

const data = await response.json();
console.log('Contract bytecode:', data.result);

// Check if address is a contract or EOA
if (data.result === '0x') {
  console.log('Address is an EOA (no contract code)');
} else {
  console.log('Address contains contract code');
}
```

```python
import requests
import json

# Get bytecode for Coinbase's cbETH contract on Ethereum
url = "https://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
payload = {
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
        "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",  # cbETH on Ethereum
        "latest"
    ],
    "id": 1
}

response = requests.post(url, json=payload)
result = response.json()

if result['result'] == '0x':
    print("Address is an EOA")
else:
    print(f"Contract bytecode: {result['result'][:100]}...")  # First 100 chars
    print(f"Bytecode length: {len(result['result'])} characters")
```

## Important Notes

### EOA vs Contract Addresses

- **Contract addresses**: Return the actual bytecode of the deployed smart contract
- **EOA addresses**: Return "0x" as they contain no contract code
- Use this method to programmatically distinguish between EOAs and contracts

### Use Cases

- **Contract verification**: Compare deployed bytecode with source code
- **Security analysis**: Analyze contract functionality and potential vulnerabilities
- **Proxy detection**: Identify proxy contracts and their implementation patterns
- **Contract interaction**: Understand contract capabilities before interaction

### Ethereum-Specific Considerations

- Centrifuge is the main Layer 1 blockchain using Proof of Stake consensus
- Bytecode format is identical to Centrifuge mainnet
- Gas costs for contract deployment and execution are significantly lower
- Full compatibility with Centrifuge smart contracts and tooling

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Centrifuge documentation](https://www.dwellir.com/docs/centrifuge).*

---

## eth_getFilterChanges - Poll filter for ch...

# eth_getFilterChanges - Poll filter for ch...

Polling method for a filter, which returns an array of events that have occurred since the last poll on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Create a log filter scoped to the latest block (requires jq)
    FILTER_ID=$(curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newFilter",
        "params": [{
          "fromBlock": "latest",
          "toBlock": "latest",
          "address": null,
          "topics": []
        }],
        "id": 1
      }' | jq -r '.result')

    # Poll for changes on that filter
    curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d "$(jq -n --arg id \"$FILTER_ID\" '{jsonrpc:\"2.0\", method:\"eth_getFilterChanges\", params:[$id], id:1}')"
```

## Response Fields

- `result` (`OBJECT, required`): `address` (string): Address from which this log originated `topics` (array of strings): Array of 0 to 4 32-byte DATA topics `data` (string): Contains non-indexed arguments of the log `blockNumber` (string): Block number where this log was included `blockHash` (string): Hash of the block where this log was included `transactionHash` (string): Hash of the transaction that created this log `transactionIndex` (string): Transaction index position in the block `logIndex` (string): Integer of the log index position in the block `removed` (boolean): true when the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
      "blockNumber": "0x1b4",
      "blockHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "transactionHash": "0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
      "transactionIndex": "0x1",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
# Create a log filter scoped to the latest block (requires jq)
FILTER_ID=$(curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": null,
      "topics": []
    }],
    "id": 1
  }' | jq -r '.result')

# Poll for changes on that filter
curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg id \"$FILTER_ID\" '{jsonrpc:\"2.0\", method:\"eth_getFilterChanges\", params:[$id], id:1}')"
```

```javascript
const endpoint = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY';

const createFilter = async () => {
  const filterResponse = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_newFilter',
      params: [{ fromBlock: 'latest', toBlock: 'latest', address: null, topics: [] }],
      id: 1
    })
  });
  const { result } = await filterResponse.json();
  return result;
};

const filterId = await createFilter();
const response = await fetch(endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getFilterChanges',
    params: [filterId],
    id: 2
  })
});

const data = await response.json();
console.log(data.result);
```

```python
import requests

url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}

filter_payload = {
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
        "fromBlock": "latest",
        "toBlock": "latest",
        "address": None,
        "topics": []
    }],
    "id": 1
}

filter_id = requests.post(url, headers=headers, json=filter_payload, timeout=10).json()['result']

changes_payload = {
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": [filter_id],
    "id": 2
}

response = requests.post(url, headers=headers, json=changes_payload, timeout=10)
print(response.json()['result'])
```

## Notes

- This method only returns changes that occurred since the last poll
- Filters timeout if not accessed within a certain time period (typically 5 minutes)
- The first call to eth\_getFilterChanges returns all events since filter creation
- Subsequent calls return only new events since the previous call
- Use eth\_getFilterLogs to retrieve all accumulated logs regardless of polling

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Centrifuge documentation](https://www.dwellir.com/docs/centrifuge).*

---

## eth_getFilterLogs - Get Filter Logs

# eth_getFilterLogs - Get Filter Logs

Returns an array of all logs matching filter with given id on the Centrifuge network. This method retrieves all accumulated logs that match the criteria of a previously created filter.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Create a filter for block 0x86d9c9 that includes Centrifuge liquidity pool events (requires jq)
    FILTER_ID=$(curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newFilter",
        "params": [{
          "fromBlock": "0x86d9c9",
          "toBlock": "0x86d9c9",
          "address": "0x2d5d7d31f671f86c782533cc367f14109a082712",
          "topics": []
        }],
        "id": 1
      }' | jq -r '.result')

    # Retrieve the logs captured by that filter
    curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d "$(jq -n --arg id \"$FILTER_ID\" '{jsonrpc:\"2.0\", method:\"eth_getFilterLogs\", params:[$id], id:1}')"
```

## Response Fields

- `result` (`OBJECT, required`): `address` (string): Address from which this log originated `topics` (array of strings): Array of 0 to 4 32-byte DATA topics. The first topic is the hash of the signature of the event `data` (string): Contains non-indexed arguments of the log `blockNumber` (string): Block number where this log was included (null when pending) `blockHash` (string): Hash of the block where this log was included (null when pending) `transactionHash` (string): Hash of the transaction that created this log (null when pending) `transactionIndex` (string): Transaction index position in the block (null when pending) `logIndex` (string): Integer of the log index position in the block (null when pending) `removed` (boolean): true when the log was removed due to a chain reorganization, false if it's a valid log

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000009876543210fedcba9876543210fedcba98765432"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
      "blockNumber": "0x1b4",
      "blockHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "transactionHash": "0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
      "transactionIndex": "0x1",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
# Create a filter for block 0x86d9c9 that includes Centrifuge liquidity pool events (requires jq)
FILTER_ID=$(curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x86d9c9",
      "toBlock": "0x86d9c9",
      "address": "0x2d5d7d31f671f86c782533cc367f14109a082712",
      "topics": []
    }],
    "id": 1
  }' | jq -r '.result')

# Retrieve the logs captured by that filter
curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg id \"$FILTER_ID\" '{jsonrpc:\"2.0\", method:\"eth_getFilterLogs\", params:[$id], id:1}')"
```

```javascript
const endpoint = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY';

const createLogsFilter = async () => {
  const payload = {
    jsonrpc: '2.0',
    method: 'eth_newFilter',
    params: [{
      fromBlock: '0x86d9c9',
      toBlock: '0x86d9c9',
      address: '0x2d5d7d31f671f86c782533cc367f14109a082712',
      topics: []
    }],
    id: 1
  };

  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });

  const { result } = await response.json();
  return result;
};

const filterId = await createLogsFilter();
const response = await fetch(endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getFilterLogs',
    params: [filterId],
    id: 2
  })
});

const data = await response.json();
console.log(data.result);
```

```python
import requests

url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}

filter_payload = {
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
        "fromBlock": "0x86d9c9",
        "toBlock": "0x86d9c9",
        "address": "0x2d5d7d31f671f86c782533cc367f14109a082712",
        "topics": []
    }],
    "id": 1
}

filter_id = requests.post(url, headers=headers, json=filter_payload, timeout=10).json()['result']

logs_payload = {
    "jsonrpc": "2.0",
    "method": "eth_getFilterLogs",
    "params": [filter_id],
    "id": 2
}

response = requests.post(url, headers=headers, json=logs_payload, timeout=10)
print(response.json()['result'])
```

## Notes

- The filter must be created first using `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`
- This method returns all logs accumulated since the filter was created
- Filters timeout if not accessed within a certain time period (typically 5 minutes)
- Use `eth_getFilterChanges` to get only new logs since the last poll
- The `removed` field helps handle chain reorganizations

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Centrifuge documentation](https://www.dwellir.com/docs/centrifuge).*

---

## eth_getLogs - Query Event Logs

# eth_getLogs - Query Event Logs

Returns an array of all logs matching a given filter object. Essential for querying historical events and monitoring smart contract activity.

## Block Range Limits

| Plan            | Maximum blocks per request |
| --------------- | -------------------------: |
| Free            |              Not available |
| Developer       |                        500 |
| Growth          |                     10,000 |
| Scale and above |                     10,000 |

Both endpoints count toward the limit: `toBlock - fromBlock + 1`.
Supply explicit numeric bounds for historical ranges, or use `blockHash` for one block.
Split longer ranges into requests within your plan limit.
See [request rules and errors](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits), including accepted block tags.

## When to Use This Method

`eth_getLogs` is crucial for:

- **Event Monitoring** - Track smart contract events and state changes
- **Historical Queries** - Search past events within a block range
- **DeFi Analytics** - Monitor trades, liquidity events, and protocol activity
- **Indexing** - Build databases of on-chain events

## Request Parameters

- `filter` (`OBJECT, required`): Supply block bounds, or blockHash for one block. Missing or null bounds default to latest. See the block range limits above.
- `filter.fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to latest.
- `filter.toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to latest.
- `filter.blockHash` (`DATA, optional`): A 32-byte block hash. Cannot be combined with non-null fromBlock or toBlock.
- `filter.address` (`DATA|Array, optional`): Contract address or array of contract addresses.
- `filter.topics` (`Array, optional`): Indexed event filters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{"fromBlock": "0x1", "toBlock": "0x1f4"}],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): `removed` - `true` if log was removed due to reorg `logIndex` - Position in the block `transactionIndex` - Transaction position in block `transactionHash` - Hash of transaction `blockHash` - Hash of block `blockNumber` - Block number `address` - Contract address `data` - Non-indexed log parameters `topics` - Array of indexed log parameters

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7d8d9ef8d8ce8992df33d8b8cf4aebabd5bd270",
        "0x0000000000000000000000004e6b5f1abfb9aa3cc5b3d8f4a7b8c2d9e3f0a1b2"
      ],
      "data": "0x000000000000000000000000000000000000000000000000016345785d8a0000",
      "blockNumber": "0x123abc",
      "blockHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      "transactionHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "transactionIndex": "0x0",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Block range exceeds plan limit

- Code: `-32005`
- Description: HTTP 200 with a JSON-RPC error. Split the range into requests within your plan limit.

### Invalid block range

- Code: `-32602`
- Description: HTTP 200 with a JSON-RPC error. Supply valid bounds or a blockHash without non-null bounds.

### Chain head unavailable

- Code: `-32000`
- Description: HTTP 200 with a JSON-RPC error. Retry shortly or use explicit hexadecimal bounds.

### Error 1

- Description: Too many logs in range

### Error 2

- Description: fromBlock > toBlock

### Error 3

- Description: Large query timeout

## Implementation Examples

The helpers below take a numeric starting height and a numeric ending height or `latest`.
They resolve `latest` once and split historical ranges into 500-block requests.
The JavaScript examples use `toQuantity` to encode block heights without leading zeroes.

curl
JavaScript
Python

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "0x86d9c9",
      "toBlock": "0x86d9c9",
      "address": "0x2d5d7d31f671f86c782533cc367f14109a082712",
      "topics": [
        "0xd5df103822011013c8c940930e5180419111c65abadd6525ca7e740d56b4703f"
      ]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface, id, zeroPadValue, toQuantity } from 'ethers';

const provider = new JsonRpcProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY');

// Advanced event monitoring system
class EventMonitor {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async getTransferEvents(tokenAddress, fromBlock, toBlock) {
    // ERC20 Transfer event signature
    const transferTopic = id('Transfer(address,address,uint256)');
    
    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: tokenAddress,
      topics: [transferTopic]
    };

    const logs = await this.getPaginatedLogs(filter);
    
    // Decode logs
    const iface = new Interface([
      'event Transfer(address indexed from, address indexed to, uint256 value)'
    ]);

    return logs.map(log => {
      const decoded = iface.parseLog({
        topics: log.topics,
        data: log.data
      });

      return {
        from: decoded.args.from,
        to: decoded.args.to,
        value: decoded.args.value.toString(),
        blockNumber: log.blockNumber,
        transactionHash: log.transactionHash,
        logIndex: log.logIndex
      };
    });
  }

  async getEventsBySignature(signature, address, fromBlock, toBlock) {
    const eventTopic = id(signature);
    
    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: address,
      topics: [eventTopic]
    };

    return await this.getPaginatedLogs(filter);
  }

  async queryWithMultipleAddresses(addresses, eventSignature, fromBlock, toBlock) {
    const eventTopic = id(eventSignature);
    
    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: addresses, // Array of addresses
      topics: [eventTopic]
    };

    const logs = await this.getPaginatedLogs(filter);
    
    // Group by address
    const grouped = {};
    for (const log of logs) {
      if (!grouped[log.address]) {
        grouped[log.address] = [];
      }
      grouped[log.address].push(log);
    }
    
    return grouped;
  }

  async getFilteredTransfers(tokenAddress, specificAddress, direction, fromBlock, toBlock) {
    const transferTopic = id('Transfer(address,address,uint256)');
    
    let topics;
    if (direction === 'from') {
      // Transfers FROM specific address
      topics = [
        transferTopic,
        zeroPadValue(specificAddress, 32),
        null
      ];
    } else if (direction === 'to') {
      // Transfers TO specific address
      topics = [
        transferTopic,
        null,
        zeroPadValue(specificAddress, 32)
      ];
    } else {
      // All transfers involving address
      const [fromLogs, toLogs] = await Promise.all([
        this.getFilteredTransfers(tokenAddress, specificAddress, 'from', fromBlock, toBlock),
        this.getFilteredTransfers(tokenAddress, specificAddress, 'to', fromBlock, toBlock)
      ]);
      return [...fromLogs, ...toLogs].sort((a, b) => a.blockNumber - b.blockNumber);
    }

    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: tokenAddress,
      topics: topics
    };

    return await this.getPaginatedLogs(filter);
  }

  async searchDeFiEvents(protocolAddress, fromBlock, toBlock) {
    // Common DeFi event signatures
    const eventSignatures = {
      swap: 'Swap(address,uint256,uint256,uint256,uint256,address)',
      addLiquidity: 'Mint(address,uint256,uint256)',
      removeLiquidity: 'Burn(address,uint256,uint256,address)',
      deposit: 'Deposit(address,uint256,uint256)',
      withdraw: 'Withdrawal(address,uint256,uint256)',
      borrow: 'Borrow(address,address,uint256,uint256,uint256)',
      repay: 'Repay(address,address,uint256,uint256)'
    };

    const events = {};
    
    for (const [name, signature] of Object.entries(eventSignatures)) {
      try {
        const logs = await this.getEventsBySignature(
          signature,
          protocolAddress,
          fromBlock,
          toBlock
        );
        
        if (logs.length > 0) {
          events[name] = logs;
        }
      } catch (error) {
        // Event might not exist in this contract
        continue;
      }
    }
    
    return events;
  }

  async getPaginatedLogs(filter, pageSize = 500) {
    const results = [];
    let currentBlock = parseInt(filter.fromBlock);
    const endBlock = filter.toBlock === 'latest' ? 
      await this.provider.getBlockNumber() : 
      parseInt(filter.toBlock);
    
    while (currentBlock <= endBlock) {
      const chunkEnd = Math.min(currentBlock + pageSize - 1, endBlock);
      
      const chunkFilter = {
        ...filter,
        fromBlock: toQuantity(currentBlock),
        toBlock: toQuantity(chunkEnd)
      };
      
      try {
        const logs = await this.provider.getLogs(chunkFilter);
        results.push(...logs);
        
        console.log(`Fetched blocks ${currentBlock} to ${chunkEnd}: ${logs.length} logs`);
      } catch (error) {
        if (error.message.includes('query returned more than')) {
          // Reduce page size and retry
          return this.getPaginatedLogs(filter, Math.floor(pageSize / 2));
        }
        throw error;
      }
      
      currentBlock = chunkEnd + 1;
    }
    
    return results;
  }

  createLiveEventStream(filter, callback) {
    const processNewBlock = async (blockNumber) => {
      const logs = await this.getPaginatedLogs({
        ...filter,
        fromBlock: toQuantity(blockNumber),
        toBlock: toQuantity(blockNumber)
      });
      
      if (logs.length > 0) {
        callback(logs);
      }
    };
    
    // Listen for new blocks
    this.provider.on('block', processNewBlock);
    
    // Return unsubscribe function
    return () => {
      this.provider.off('block', processNewBlock);
    };
  }
}

// NFT event monitoring
class NFTEventTracker extends EventMonitor {

  async getERC721Transfers(contractAddress, fromBlock, toBlock) {
    const transferTopic = id('Transfer(address,address,uint256)');
    
    const logs = await this.getPaginatedLogs({
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: contractAddress,
      topics: [transferTopic]
    });

    const iface = new Interface([
      'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)'
    ]);

    return logs.map(log => {
      const decoded = iface.parseLog({
        topics: log.topics,
        data: log.data
      });

      return {
        from: decoded.args.from,
        to: decoded.args.to,
        tokenId: decoded.args.tokenId.toString(),
        blockNumber: log.blockNumber,
        transactionHash: log.transactionHash,
        isMint: decoded.args.from === '0x0000000000000000000000000000000000000000',
        isBurn: decoded.args.to === '0x0000000000000000000000000000000000000000'
      };
    });
  }

  async getERC1155Transfers(contractAddress, fromBlock, toBlock) {
    const singleTransferTopic = id('TransferSingle(address,address,address,uint256,uint256)');
    const batchTransferTopic = id('TransferBatch(address,address,address,uint256[],uint256[])');
    
    const [singleLogs, batchLogs] = await Promise.all([
      this.getPaginatedLogs({
        fromBlock: toQuantity(fromBlock),
        toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
        address: contractAddress,
        topics: [singleTransferTopic]
      }),
      this.getPaginatedLogs({
        fromBlock: toQuantity(fromBlock),
        toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
        address: contractAddress,
        topics: [batchTransferTopic]
      })
    ]);
    
    return {
      single: singleLogs,
      batch: batchLogs,
      total: singleLogs.length + batchLogs.length
    };
  }
}

// Usage examples
const monitor = new EventMonitor(provider);

// Get transfer events for a token
const transfers = await monitor.getTransferEvents(
  '0xTokenAddress',
  12345678,
  'latest'
);

// Monitor specific address activity
const userTransfers = await monitor.getFilteredTransfers(
  '0xTokenAddress',
  '0xUserAddress',
  'both', // 'from', 'to', or 'both'
  12345678,
  'latest'
);

// Search DeFi protocol events
const defiEvents = await monitor.searchDeFiEvents(
  '0xProtocolAddress',
  12345678,
  12345778
);

// Create live event stream
const unsubscribe = monitor.createLiveEventStream(
  {
    address: '0xTokenAddress',
    topics: [id('Transfer(address,address,uint256)')]
  },
  (logs) => {
    console.log('New events:', logs);
  }
);
```

```python
from web3 import Web3
from eth_utils import event_signature_to_log_topic, to_hex
import json
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta

w3 = Web3(Web3.HTTPProvider('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'))

class LogAnalyzer:
    """Analyze and query event logs on Centrifuge Mainnet"""
    
    def __init__(self, w3_instance):
        self.w3 = w3_instance
    
    def get_transfer_events(
        self,
        token_address: str,
        from_block: int,
        to_block: str = 'latest',
        from_address: Optional[str] = None,
        to_address: Optional[str] = None
    ) -> List[Dict[str, Any]]:
        """Get ERC20 transfer events with optional filtering"""
        
        # Transfer event signature
        transfer_topic = self.w3.keccak(text='Transfer(address,address,uint256)').hex()
        
        # Build topics array
        topics = [transfer_topic]
        
        if from_address:
            topics.append(self._address_to_topic(from_address))
        else:
            topics.append(None)
        
        if to_address:
            topics.append(self._address_to_topic(to_address))
        
        # Create filter
        filter_params = {
            'fromBlock': from_block,
            'toBlock': to_block,
            'address': token_address,
            'topics': topics
        }
        
        # Get logs
        logs = self.get_logs_paginated(filter_params)
        
        # Decode logs
        transfers = []
        for log in logs:
            transfers.append({
                'from': self._topic_to_address(log['topics'][1]),
                'to': self._topic_to_address(log['topics'][2]),
                'value': int(log['data'], 16) if log['data'] != '0x' else 0,
                'block_number': log['blockNumber'],
                'transaction_hash': log['transactionHash'].hex(),
                'log_index': log['logIndex'],
                'address': log['address']
            })
        
        return transfers
    
    def _address_to_topic(self, address: str) -> str:
        """Convert address to topic format"""
        return '0x' + address[2:].lower().zfill(64)
    
    def _topic_to_address(self, topic: str) -> str:
        """Convert topic to address format"""
        return '0x' + topic.hex()[-40:]
    
    def get_events_by_signature(
        self,
        event_signature: str,
        contract_address: Optional[str] = None,
        from_block: int = 0,
        to_block: str = 'latest'
    ) -> List[Dict[str, Any]]:
        """Get events by signature"""
        
        event_topic = self.w3.keccak(text=event_signature).hex()
        
        filter_params = {
            'fromBlock': from_block,
            'toBlock': to_block,
            'topics': [event_topic]
        }
        
        if contract_address:
            filter_params['address'] = contract_address
        
        logs = self.get_logs_paginated(filter_params)
        
        return [{
            'address': log['address'],
            'topics': [t.hex() for t in log['topics']],
            'data': log['data'],
            'block_number': log['blockNumber'],
            'transaction_hash': log['transactionHash'].hex(),
            'log_index': log['logIndex']
        } for log in logs]
    
    def search_defi_activity(
        self,
        protocol_address: str,
        from_block: int,
        to_block: str = 'latest'
    ) -> Dict[str, List[Dict]]:
        """Search for common DeFi events"""
        
        event_signatures = {
            'swaps': 'Swap(address,uint256,uint256,uint256,uint256,address)',
            'liquidity_added': 'Mint(address,uint256,uint256)',
            'liquidity_removed': 'Burn(address,uint256,uint256,address)',
            'deposits': 'Deposit(address,uint256)',
            'withdrawals': 'Withdrawal(address,uint256)',
            'borrows': 'Borrow(address,address,uint256,uint256,uint256)',
            'repayments': 'Repay(address,address,uint256,uint256)'
        }
        
        results = {}
        
        for event_type, signature in event_signatures.items():
            try:
                logs = self.get_events_by_signature(
                    signature,
                    protocol_address,
                    from_block,
                    to_block
                )
                
                if logs:
                    results[event_type] = logs
            except Exception as e:
                # Event might not exist in this contract
                continue
        
        return results
    
    def get_nft_transfers(
        self,
        nft_address: str,
        from_block: int,
        to_block: str = 'latest',
        token_id: Optional[int] = None
    ) -> List[Dict[str, Any]]:
        """Get NFT transfer events (ERC721)"""
        
        # Transfer event with tokenId as indexed parameter
        transfer_topic = self.w3.keccak(text='Transfer(address,address,uint256)').hex()
        
        topics = [transfer_topic, None, None]
        
        if token_id is not None:
            topics.append(to_hex(token_id).zfill(66))
        
        filter_params = {
            'fromBlock': from_block,
            'toBlock': to_block,
            'address': nft_address,
            'topics': topics
        }
        
        logs = self.get_logs_paginated(filter_params)
        
        transfers = []
        for log in logs:
            from_addr = self._topic_to_address(log['topics'][1])
            to_addr = self._topic_to_address(log['topics'][2])
            
            transfers.append({
                'from': from_addr,
                'to': to_addr,
                'token_id': int(log['topics'][3].hex(), 16) if len(log['topics']) > 3 else int(log['data'], 16),
                'is_mint': from_addr == '0x0000000000000000000000000000000000000000',
                'is_burn': to_addr == '0x0000000000000000000000000000000000000000',
                'block_number': log['blockNumber'],
                'transaction_hash': log['transactionHash'].hex(),
                'log_index': log['logIndex']
            })
        
        return transfers
    
    def get_logs_paginated(
        self,
        filter_params: Dict,
        page_size: int = 500
    ) -> List[Dict[str, Any]]:
        """Get logs with pagination to avoid query limits"""
        
        all_logs = []
        from_block = filter_params['fromBlock']
        to_block = filter_params['toBlock']
        
        if to_block == 'latest':
            to_block = self.w3.eth.block_number
        
        current_block = from_block
        
        while current_block <= to_block:
            chunk_end = min(current_block + page_size - 1, to_block)
            
            chunk_filter = {
                **filter_params,
                'fromBlock': current_block,
                'toBlock': chunk_end
            }
            
            try:
                logs = self.w3.eth.get_logs(chunk_filter)
                all_logs.extend(logs)
                
                print(f"Fetched blocks {current_block} to {chunk_end}: {len(logs)} logs")
                
            except Exception as e:
                if 'query returned more than' in str(e):
                    # Reduce page size and retry
                    if page_size > 10:
                        return self.get_logs_paginated(filter_params, page_size // 2)
                    else:
                        raise Exception("Block range too large even with minimum page size")
                else:
                    raise e
            
            current_block = chunk_end + 1
        
        return all_logs
    
    def analyze_event_patterns(
        self,
        logs: List[Dict]
    ) -> Dict[str, Any]:
        """Analyze patterns in event logs"""
        
        if not logs:
            return {'error': 'No logs to analyze'}
        
        # Group by block
        blocks = {}
        for log in logs:
            block = log['blockNumber']
            if block not in blocks:
                blocks[block] = []
            blocks[block].append(log)
        
        # Group by transaction
        transactions = {}
        for log in logs:
            tx = log['transactionHash'].hex() if hasattr(log['transactionHash'], 'hex') else log['transactionHash']
            if tx not in transactions:
                transactions[tx] = []
            transactions[tx].append(log)
        
        # Find most active addresses
        addresses = {}
        for log in logs:
            addr = log['address']
            if addr not in addresses:
                addresses[addr] = 0
            addresses[addr] += 1
        
        sorted_addresses = sorted(addresses.items(), key=lambda x: x[1], reverse=True)
        
        return {
            'total_logs': len(logs),
            'unique_blocks': len(blocks),
            'unique_transactions': len(transactions),
            'unique_addresses': len(addresses),
            'most_active_addresses': sorted_addresses[:10],
            'logs_per_block': {
                'average': len(logs) / len(blocks) if blocks else 0,
                'max': max(len(b) for b in blocks.values()) if blocks else 0,
                'min': min(len(b) for b in blocks.values()) if blocks else 0
            },
            'logs_per_transaction': {
                'average': len(logs) / len(transactions) if transactions else 0,
                'max': max(len(t) for t in transactions.values()) if transactions else 0,
                'min': min(len(t) for t in transactions.values()) if transactions else 0
            }
        }
    
    def export_logs_to_csv(
        self,
        logs: List[Dict],
        filename: str
    ):
        """Export logs to CSV file"""
        
        import csv
        
        if not logs:
            return
        
        # Get all unique keys
        keys = set()
        for log in logs:
            keys.update(log.keys())
        
        with open(filename, 'w', newline='') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=sorted(keys))
            writer.writeheader()
            
            for log in logs:
                # Convert bytes to hex strings
                row = {}
                for key, value in log.items():
                    if isinstance(value, bytes):
                        row[key] = value.hex()
                    else:
                        row[key] = value
                writer.writerow(row)
        
        print(f"Exported {len(logs)} logs to {filename}")

# Usage examples
analyzer = LogAnalyzer(w3)

# Get token transfers
transfers = analyzer.get_transfer_events(
    token_address='0xTokenAddress',
    from_block=12345678,
    to_block='latest',
    from_address='0xUserAddress'  # Optional filter
)

print(f"Found {len(transfers)} transfers")
for transfer in transfers[:5]:
    print(f"From: {transfer['from'][:10]}... To: {transfer['to'][:10]}... Value: {transfer['value']}")

# Search DeFi activity
defi_events = analyzer.search_defi_activity(
    protocol_address='0xProtocolAddress',
    from_block=12345678
)

for event_type, events in defi_events.items():
    print(f"{event_type}: {len(events)} events")

# Get NFT transfers
nft_transfers = analyzer.get_nft_transfers(
    nft_address='0xNFTAddress',
    from_block=12345678
)

mints = [t for t in nft_transfers if t['is_mint']]
print(f"Found {len(mints)} NFT mints")

# Analyze event patterns
pattern_analysis = analyzer.analyze_event_patterns(transfers)
print(f"Analysis: {json.dumps(pattern_analysis, indent=2)}")
```

## Advanced Usage

### Multiple Address Filtering

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "0x1",
    "toBlock": "0xc8",
    "address": [
      "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "0x4200000000000000000000000000000000000006"
    ],
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
    ]
  }],
  "id": 1
}
```

### Topic Filtering with OR Logic

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "0x1",
    "toBlock": "0xc8",
    "topics": [
      [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
      ]
    ]
  }],
  "id": 1
}
```

## Notes

- Centrifuge supports **historical log queries** back to genesis block
- **Query limits**: Maximum 10,000 results per request
- **Block range limits**: Developer 500; Growth, Scale, and Enterprise 10,000 blocks per request
- **Topic arrays**: Support up to 4 topics with OR logic within each position
- **Performance tip**: Use specific address filters to improve query speed
- **Event signatures**: First topic is always the keccak256 hash of the event signature

## Common Use Cases

### 1. Token Balance History

```javascript
// Track historical token balance changes
async function getBalanceHistory(tokenAddress, userAddress, fromBlock) {
  const monitor = new EventMonitor(provider);
  
  // Get all transfers involving the user
  const logs = await monitor.getFilteredTransfers(
    tokenAddress,
    userAddress,
    'both',
    fromBlock,
    'latest'
  );
  
  // Calculate balance changes
  const balanceChanges = [];
  let currentBalance = 0n;
  
  for (const log of logs) {
    const iface = new Interface([
      'event Transfer(address indexed from, address indexed to, uint256 value)'
    ]);
    
    const decoded = iface.parseLog({
      topics: log.topics,
      data: log.data
    });
    
    const change = decoded.args.from.toLowerCase() === userAddress.toLowerCase() ?
      -decoded.args.value : decoded.args.value;
    
    currentBalance += change;
    
    balanceChanges.push({
      blockNumber: log.blockNumber,
      transactionHash: log.transactionHash,
      change: change.toString(),
      balance: currentBalance.toString(),
      type: change < 0 ? 'outgoing' : 'incoming'
    });
  }
  
  return balanceChanges;
}
```

### 2. DEX Trade Monitoring

```javascript
// Monitor DEX trading activity
async function monitorDEXTrades(dexAddress, fromBlock) {
  const swapTopic = id('Swap(address,address,int256,int256,uint160,uint128,int24)');
  
  const logs = await new EventMonitor(provider).getPaginatedLogs({
    fromBlock: toQuantity(fromBlock),
    toBlock: 'latest',
    address: dexAddress,
    topics: [swapTopic]
  });
  
  const trades = logs.map(log => {
    // Decode Uniswap V3 swap event
    const iface = new Interface([
      'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)'
    ]);
    
    const decoded = iface.parseLog({
      topics: log.topics,
      data: log.data
    });
    
    return {
      sender: decoded.args.sender,
      recipient: decoded.args.recipient,
      amount0: decoded.args.amount0.toString(),
      amount1: decoded.args.amount1.toString(),
      price: Number(decoded.args.sqrtPriceX96) ** 2 / (2 ** 192),
      blockNumber: log.blockNumber,
      transactionHash: log.transactionHash
    };
  });
  
  return trades;
}
```

### 3. Contract Event Indexer

```javascript
// Build an event index for a contract
class EventIndexer {
  constructor(provider, contractAddress, abi) {
    this.provider = provider;
    this.contractAddress = contractAddress;
    this.iface = new Interface(abi);
    this.eventIndex = new Map();
  }
  
  async indexEvents(fromBlock, toBlock) {
    // Get all events for the contract
    const logs = await new EventMonitor(this.provider).getPaginatedLogs({
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: this.contractAddress
    });
    
    for (const log of logs) {
      try {
        const parsed = this.iface.parseLog({
          topics: log.topics,
          data: log.data
        });
        
        if (!this.eventIndex.has(parsed.name)) {
          this.eventIndex.set(parsed.name, []);
        }
        
        this.eventIndex.get(parsed.name).push({
          args: Object.fromEntries(
            Object.entries(parsed.args).filter(([key]) => isNaN(key))
          ),
          blockNumber: log.blockNumber,
          transactionHash: log.transactionHash,
          logIndex: log.logIndex
        });
      } catch {
        // Unknown event
      }
    }
    
    return this.getStatistics();
  }
  
  getStatistics() {
    const stats = {};
    
    for (const [eventName, events] of this.eventIndex) {
      stats[eventName] = {
        count: events.length,
        firstBlock: Math.min(...events.map(e => e.blockNumber)),
        lastBlock: Math.max(...events.map(e => e.blockNumber))
      };
    }
    
    return stats;
  }
}
```

---

## eth_getStorageAt - Get Contract Storage V...

# eth_getStorageAt - Get Contract Storage V...

Retrieves the value from a storage position at a given address on the Centrifuge network. This method allows direct access to contract storage slots, enabling you to read contract state variables, proxy implementation addresses, and other stored data.

## Request Parameters

- `address` (`string, required`): The 20-byte address of the contract whose storage you want to read
- `position` (`string, required`): The hex-encoded storage position/slot number (32 bytes)
- `blockNumber` (`string, required`): Block number in hex, or block tag ("latest", "earliest", "pending")

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getStorageAt",
  "params": [
    "<address>",
    "<position>",
    "<blockNumber>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Returns a 32-byte hex string representing the storage value. Values are left-padded with zeros if smaller than 32 bytes.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Read storage slot 0 from USDC contract on Ethereum
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Read storage from Centrifuge USDC contract
const getStorage = async () => {
  const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_getStorageAt',
      params: [
        '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Centrifuge USDC
        '0x0', // Storage slot 0
        'latest'
      ],
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Calculate mapping storage position
const getMappingSlot = (key, slot) => {
  const keyPadded = key.padStart(64, '0');
  const slotPadded = slot.toString(16).padStart(64, '0');
  return web3.utils.keccak256('0x' + keyPadded + slotPadded);
};
```

```python
import requests
from web3 import Web3

# Read storage from contract
def get_storage_at(address, position, block='latest'):
    payload = {
        "jsonrpc": "2.0",
        "method": "eth_getStorageAt",
        "params": [address, position, block],
        "id": 1
    }
    
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json=payload,
        headers={'Content-Type': 'application/json'}
    )
    
    return response.json()['result']

# Example: Read from Centrifuge USDC contract
usdc_address = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
storage_value = get_storage_at(usdc_address, '0x0')

# Calculate mapping storage position
def get_mapping_slot(key, slot):
    key_padded = key.zfill(64)
    slot_padded = hex(slot)[2:].zfill(64)
    return Web3.keccak(bytes.fromhex(key_padded + slot_padded)).hex()

# Example: Get balance mapping for an address
balance_slot = get_mapping_slot('000000000000000000000000YourAddress', 9)
balance = get_storage_at(usdc_address, balance_slot)
```

## Use Cases

- **Contract State Inspection**: Read private or internal variables
- **Proxy Implementation**: Get implementation address from proxy contracts
- **Token Balances**: Access balance mappings directly
- **Access Control**: Check role assignments and permissions
- **Debugging**: Investigate contract state during development

## Important Notes

- Storage values are always 32 bytes (64 hex characters plus 0x prefix)
- Unused storage slots return `0x0000000000000000000000000000000000000000000000000000000000000000`
- Storage layout depends on Solidity version and compiler optimizations
- For dynamic arrays, slot contains length; actual data starts at `keccak256(slot)`
- Packed structs may share storage slots for gas optimization

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Centrifuge documentation](https://www.dwellir.com/docs/centrifuge).*

---

## eth_getTransactionByHash - Get Transactio...

# eth_getTransactionByHash - Get Transactio...

Returns information about a transaction requested by transaction hash. Essential for tracking transaction status and details.

## When to Use This Method

`eth_getTransactionByHash` is crucial for:

- **Transaction Tracking** - Monitor transaction status after submission
- **Payment Verification** - Confirm payment details and recipients
- **Transaction Explorers** - Build transaction detail pages
- **Debugging** - Investigate failed or stuck transactions

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Payment Verification System

```javascript
// Verify payment received
async function verifyPayment(txHash, expectedAmount, expectedRecipient) {
  const tx = await provider.getTransaction(txHash);
  
  if (!tx) {
    return { valid: false, reason: 'Transaction not found' };
  }
  
  // Check recipient
  if (tx.to?.toLowerCase() !== expectedRecipient.toLowerCase()) {
    return { valid: false, reason: 'Wrong recipient' };
  }
  
  // Check amount
  if (tx.value.toString() !== expectedAmount) {
    return { valid: false, reason: 'Wrong amount' };
  }
  
  // Check confirmations
  if (!tx.blockNumber) {
    return { valid: false, reason: 'Transaction pending' };
  }
  
  const receipt = await provider.getTransactionReceipt(txHash);
  if (receipt.status === 0) {
    return { valid: false, reason: 'Transaction failed' };
  }
  
  return {
    valid: true,
    confirmations: tx.confirmations,
    blockNumber: tx.blockNumber
  };
}
```

### 2. Transaction History Builder

```javascript
// Build transaction history for address
async function getAddressTransactions(address, txHashes) {
  const transactions = [];
  
  for (const hash of txHashes) {
    const tx = await provider.getTransaction(hash);
    
    if (!tx) continue;
    
    const isIncoming = tx.to?.toLowerCase() === address.toLowerCase();
    const isOutgoing = tx.from.toLowerCase() === address.toLowerCase();
    
    transactions.push({
      hash: tx.hash,
      type: isIncoming ? 'incoming' : 'outgoing',
      from: tx.from,
      to: tx.to,
      value: ethers.formatEther(tx.value),
      timestamp: tx.blockNumber ? 
        (await provider.getBlock(tx.blockNumber)).timestamp : null,
      status: tx.blockNumber ? 'confirmed' : 'pending',
      gasPrice: tx.gasPrice ? ethers.formatGwei(tx.gasPrice) : null,
      confirmations: tx.confirmations
    });
  }
  
  return transactions.sort((a, b) => b.timestamp - a.timestamp);
}
```

### 3. Gas Price Analysis

```javascript
// Analyze gas usage patterns
async function analyzeGasUsage(txHash) {
  const tx = await provider.getTransaction(txHash);
  
  if (!tx) {
    throw new Error('Transaction not found');
  }
  
  const receipt = await provider.getTransactionReceipt(txHash);
  const block = await provider.getBlock(tx.blockNumber);
  
  return {
    txHash: tx.hash,
    gasLimit: tx.gasLimit.toString(),
    gasUsed: receipt ? receipt.gasUsed.toString() : null,
    gasPrice: tx.gasPrice ? ethers.formatGwei(tx.gasPrice) : null,
    maxFeePerGas: tx.maxFeePerGas ? ethers.formatGwei(tx.maxFeePerGas) : null,
    maxPriorityFee: tx.maxPriorityFeePerGas ? 
      ethers.formatGwei(tx.maxPriorityFeePerGas) : null,
    baseFee: block.baseFeePerGas ? 
      ethers.formatGwei(block.baseFeePerGas) : null,
    efficiency: receipt ? 
      ((Number(receipt.gasUsed) / Number(tx.gasLimit)) * 100).toFixed(2) + '%' : null,
    totalCost: receipt && tx.gasPrice ? 
      ethers.formatEther(receipt.gasUsed * tx.gasPrice) : null
  };
}
```

---

## eth_getTransactionCount - Get Centrifuge...

# eth_getTransactionCount - Get Centrifuge...

Retrieves the number of transactions sent from an account on the Centrifuge network. This method returns the account's nonce, which is essential for transaction ordering and preventing replay attacks. The nonce represents the count of confirmed transactions from the specified address.

## Description

The `eth_getTransactionCount` method is crucial for Centrifuge blockchain interaction as it provides the current transaction count (nonce) for any account. This value must be included in every transaction to ensure proper ordering and prevent duplicate transactions on the Centrifuge Mainnet network.

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: invalid address"
  }
}
```

## Use Cases

- **Transaction Building**: Get next nonce for new transactions
- **Wallet Management**: Track account activity and transaction history
- **Nonce Management**: Prevent transaction conflicts in DApps
- **Account Analysis**: Determine if address is active or new
- **Batch Transactions**: Sequence multiple transactions correctly

## Response Examples

### Latest Block Transaction Count

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c"
}
```

### Pending Transaction Count

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "0x1e"
}
```

## Important Notes

### Nonce Management

- **Transaction Ordering**: Each transaction must use the next sequential nonce
- **Pending vs Confirmed**: Use "pending" to include mempool transactions when building new transactions
- **Failed Transactions**: Failed transactions still consume the nonce and increment the count
- **Nonce Gaps**: Transactions with gaps in nonce sequence will be held until earlier nonces are filled

### Best Practices

- Always use "pending" when preparing new transactions to avoid nonce conflicts
- Cache nonce values briefly but refresh for each new transaction batch
- Handle nonce collisions by incrementing and retrying
- Monitor both confirmed and pending counts for wallet applications

### Centrifuge Network Specifics

- Centrifuge uses a sequential nonce system for transaction ordering
- Transaction finality depends on network confirmation requirements
- Nonce management is crucial for Centrifuge DApp development
- Consider batch transaction sequencing for gas optimization

### Common Use Cases

1. **Wallet Integration**: Track user transaction history
2. **DApp Development**: Sequence contract interactions
3. **Transaction Builders**: Generate properly ordered transactions
4. **Account Analysis**: Determine account activity levels
5. **Automated Systems**: Manage nonce for bot transactions

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Centrifuge documentation](https://www.dwellir.com/docs/centrifuge).*

---

## eth_getTransactionReceipt - Get Receipt

# eth_getTransactionReceipt - Get Receipt

Returns the receipt of a transaction by transaction hash. Provides execution status, gas consumption, and emitted logs.

## When to Use This Method

`eth_getTransactionReceipt` is essential for:

- **Transaction Confirmation** - Verify successful execution
- **Event Monitoring** - Access emitted logs and events
- **Gas Analysis** - Track actual gas consumption
- **Contract Deployment** - Get deployed contract addresses

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Smart Contract Event Monitoring

```javascript
// Monitor DeFi protocol events
async function monitorDeFiEvents(txHash) {
  const DEFI_ABI = [
    "event Deposit(address indexed user, uint256 amount, uint256 shares)",
    "event Withdraw(address indexed user, uint256 amount, uint256 shares)",
    "event Swap(address indexed user, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut)"
  ];
  
  const processor = new ReceiptProcessor(provider);
  const events = await processor.parseEvents(txHash, DEFI_ABI);
  
  for (const event of events) {
    switch(event.name) {
      case 'Deposit':
        console.log(`User ${event.args.user} deposited ${event.args.amount}`);
        break;
      case 'Withdraw':
        console.log(`User ${event.args.user} withdrew ${event.args.amount}`);
        break;
      case 'Swap':
        console.log(`Swap: ${event.args.amountIn} ${event.args.tokenIn} -> ${event.args.amountOut} ${event.args.tokenOut}`);
        break;
    }
  }
  
  return events;
}
```

### 2. Failed Transaction Debugging

```javascript
// Debug failed transactions
async function debugFailedTransaction(txHash) {
  const receipt = await provider.getTransactionReceipt(txHash);
  
  if (!receipt) {
    return { error: 'Receipt not found' };
  }
  
  if (receipt.status === 1) {
    return { status: 'success' };
  }
  
  // Get transaction details for more context
  const tx = await provider.getTransaction(txHash);
  
  // Try to decode revert reason
  try {
    const result = await provider.call({
      to: tx.to,
      from: tx.from,
      data: tx.data,
      value: tx.value,
      gasLimit: tx.gasLimit
    }, tx.blockNumber - 1);
  } catch (error) {
    return {
      status: 'failed',
      gasUsed: receipt.gasUsed.toString(),
      gasLimit: tx.gasLimit.toString(),
      revertReason: error.reason || error.message,
      block: receipt.blockNumber
    };
  }
}
```

### 3. Multi-Transaction Batch Analysis

```javascript
// Analyze batch of transactions
async function analyzeBatch(txHashes) {
  const processor = new ReceiptProcessor(provider);
  const results = [];
  
  for (const hash of txHashes) {
    const receipt = await processor.getReceipt(hash);
    const cost = await processor.calculateTotalCost(hash);
    
    results.push({
      hash: hash,
      status: receipt?.status,
      gasUsed: receipt?.gasUsed,
      totalCost: cost?.totalCost,
      l1Cost: cost?.l1Cost,
      blockNumber: receipt?.blockNumber
    });
  }
  
  // Calculate statistics
  const successful = results.filter(r => r.status === 'success').length;
  const totalGas = results.reduce((sum, r) => sum + BigInt(r.gasUsed || 0), 0n);
  
  return {
    transactions: results,
    statistics: {
      total: txHashes.length,
      successful: successful,
      failed: txHashes.length - successful,
      totalGasUsed: totalGas.toString()
    }
  };
}
```

---

## eth_hashrate - Get node hashrate

# eth_hashrate - Get node hashrate

Get node hashrate on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_hashrate",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_maxPriorityFeePerGas - Get priority f...

# eth_maxPriorityFeePerGas - Get priority f...

Returns the priority fee needed for inclusion in the next block on the Centrifuge network. This method is essential for EIP-1559 transactions, helping you determine the appropriate tip to incentivize miners.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_maxPriorityFeePerGas",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `QUANTITY` - The hex-encoded priority fee per gas in wei needed for inclusion in the next block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x77359400"
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_mining - Check if node is mining

# eth_mining - Check if node is mining

Check if node is mining on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_mining",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_newBlockFilter - Subscribe to new blocks

# eth_newBlockFilter - Subscribe to new blocks

Subscribe to new blocks on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newBlockFilter",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newBlockFilter',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_newFilter - Create event filter

# eth_newFilter - Create event filter

Creates a filter object, based on filter options, to notify when the state changes (logs) on the Centrifuge network. This method is essential for tracking smart contract events and state changes.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newFilter",
        "params": [{
          "fromBlock": "0x1",
          "toBlock": "0x2",
          "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
          "topics": [
            "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"
          ]
        }],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `filterID` (string): A hexadecimal filter identifier to be used with: `eth_getFilterChanges` - Get new logs since last poll `eth_getFilterLogs` - Get all accumulated logs `eth_uninstallFilter` - Remove the filter when no longer needed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x990a0ab959f87cc519ae825a7e6e7a46"
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1",
      "toBlock": "0x2",
      "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
      "topics": [
        "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"
      ]
    }],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newFilter',
    params: [{
      fromBlock: '0x1',
      toBlock: '0x2',
      address: '0x8888f1f195afa192cfee860698584c030f4c9db1',
      topics: [
        '0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b'
      ]
    }],
    id: 1
  })
});

const data = await response.json();
const filterID = data.result;
console.log('Filter ID:', filterID);
```

```python
import requests
import json

url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}
payload = {
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
        "fromBlock": "0x1",
        "toBlock": "0x2",
        "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
        "topics": [
            "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"
        ]
    }],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
data = response.json()
filter_id = data['result']
print(f'Filter ID: {filter_id}')
```

## Advanced Usage

### Monitor Multiple Contracts

```json
{
  "params": [{
    "fromBlock": "latest",
    "address": [
      "0x1234567890abcdef1234567890abcdef12345678",
      "0xabcdef1234567890abcdef1234567890abcdef12"
    ]
  }]
}
```

### Complex Topic Filtering

```json
{
  "params": [{
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",  // Transfer event
      null,  // Any sender
      [      // Specific recipients
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ]
    ]
  }]
}
```

### Monitor All Events from Latest Block

```json
{
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest"
  }]
}
```

## Workflow Example

```javascript
// 1. Create filter
const createFilter = await fetch(url, {
  method: 'POST',
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newFilter',
    params: [{ fromBlock: 'latest' }],
    id: 1
  })
});
const { result: filterID } = await createFilter.json();

// 2. Poll for changes
const getChanges = await fetch(url, {
  method: 'POST',
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getFilterChanges',
    params: [filterID],
    id: 2
  })
});
const { result: logs } = await getChanges.json();

// 3. Clean up
const uninstall = await fetch(url, {
  method: 'POST',
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_uninstallFilter',
    params: [filterID],
    id: 3
  })
});
```

## Notes

- **Block Range Limits**: Free plans typically limited to 5 blocks, paid plans up to 10,000 blocks
- **Filter Timeout**: Filters expire after \~5 minutes of inactivity - poll regularly with `eth_getFilterChanges`
- **Topics Order**: Topics are order-dependent; the first topic is usually the event signature hash
- **Filter Management**: Always uninstall filters when done to free up resources
- **Performance**: Create specific filters to reduce the amount of data processed

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Centrifuge documentation](https://www.dwellir.com/docs/centrifuge).*

---

## eth_newPendingTransactionFilter - Monitor...

# eth_newPendingTransactionFilter - Monitor...

Monitor pending transactions on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newPendingTransactionFilter",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newPendingTransactionFilter',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_protocolVersion - Get protocol version

# eth_protocolVersion - Get protocol version

Get protocol version on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_protocolVersion",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_sendRawTransaction - Broadcast Signed...

# eth_sendRawTransaction - Broadcast Signed...

Submits a pre-signed transaction to the network for broadcast and execution. Returns the transaction hash if successful.

## When to Use This Method

`eth_sendRawTransaction` is required for:

- **Sending ETH** - Transfer value between accounts
- **Token Transfers** - Execute ERC20/NFT transfers
- **Contract Interactions** - Call state-changing functions
- **Contract Deployment** - Deploy new smart contracts

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Common Use Cases

### 1. Safe Transaction Broadcasting

```javascript
// Broadcast with safety checks
async function safeBroadcast(wallet, transaction) {
  // Pre-flight checks
  const balance = await wallet.provider.getBalance(wallet.address);
  const estimatedCost = transaction.gasLimit * transaction.maxFeePerGas;
  
  if (balance < estimatedCost + transaction.value) {
    throw new Error('Insufficient balance for transaction');
  }
  
  // Check nonce
  const expectedNonce = await wallet.provider.getTransactionCount(wallet.address);
  if (transaction.nonce && transaction.nonce !== expectedNonce) {
    console.warn(`Nonce mismatch: expected ${expectedNonce}, got ${transaction.nonce}`);
  }
  
  // Sign transaction
  const signedTx = await wallet.signTransaction(transaction);
  
  // Broadcast with retry
  let attempts = 0;
  while (attempts < 3) {
    try {
      const txHash = await wallet.provider.send('eth_sendRawTransaction', [signedTx]);
      return txHash;
    } catch (error) {
      if (error.message.includes('already known')) {
        // Transaction already sent
        return ethers.Transaction.from(signedTx).hash;
      }
      attempts++;
      if (attempts === 3) throw error;
      await new Promise(r => setTimeout(r, 1000 * attempts));
    }
  }
}
```

### 2. Optimized Gas Strategy

```javascript
// Dynamic gas price management
async function optimizedSend(wallet, to, value) {
  const provider = wallet.provider;
  
  // Get network conditions
  const [block, feeData, gasPrice] = await Promise.all([
    provider.getBlock('latest'),
    provider.getFeeData(),
    provider.getGasPrice()
  ]);
  
  // Calculate optimal fees
  const baseFee = block.baseFeePerGas;
  const priorityFee = feeData.maxPriorityFeePerGas;
  
  // Adjust based on network congestion
  const congestionFactor = Number(baseFee) / Number(parseUnits('10', 'gwei'));
  const adjustedPriorityFee = priorityFee * BigInt(Math.ceil(congestionFactor));
  
  const transaction = {
    to: to,
    value: parseEther(value),
    type: 2,
    chainId: 1,
    maxFeePerGas: baseFee * 2n + adjustedPriorityFee,
    maxPriorityFeePerGas: adjustedPriorityFee,
    gasLimit: 21000n
  };
  
  const signedTx = await wallet.signTransaction(transaction);
  return await provider.send('eth_sendRawTransaction', [signedTx]);
}
```

### 3. Transaction Queue Management

```javascript
// Manage transaction queue
class TransactionQueue {
  constructor(wallet) {
    this.wallet = wallet;
    this.queue = [];
    this.processing = false;
  }
  
  async add(transaction) {
    this.queue.push(transaction);
    if (!this.processing) {
      this.process();
    }
  }
  
  async process() {
    this.processing = true;
    
    while (this.queue.length > 0) {
      const tx = this.queue.shift();
      
      try {
        // Add nonce
        tx.nonce = await this.wallet.provider.getTransactionCount(this.wallet.address);
        
        // Sign and send
        const signedTx = await this.wallet.signTransaction(tx);
        const hash = await this.wallet.provider.send('eth_sendRawTransaction', [signedTx]);
        
        console.log(`Transaction sent: ${hash}`);
        
        // Wait for confirmation before next
        await this.wallet.provider.waitForTransaction(hash);
      } catch (error) {
        console.error('Transaction failed:', error);
        // Optionally re-queue or handle error
      }
    }
    
    this.processing = false;
  }
}
```

---

## eth_sendTransaction - Send transaction (w...

# eth_sendTransaction - Send transaction (w...

> **Important**: Dwellir's shared Centrifuge endpoints do not manage user private keys. JSON-RPC nodes cannot unlock your account, so `eth_sendTransaction` calls will fail. Sign transactions client-side and broadcast them with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/centrifuge/eth_sendRawTransaction).

## Why this method is disabled on shared nodes

- [`eth_sendTransaction` requires the node to hold and unlock the `from` account's private key](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction).
- Managed infrastructure providers disable it for security reasons rather than storing customer keys on shared servers (for example, [Infura explicitly blocks the method on shared endpoints](https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_sendtransaction)).

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (defaults to estimate if omitted)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei for legacy transactions
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Priority fee in wei (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Amount of native token to transfer
- `data` (`DATA, optional`): Contract call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): Transaction hash returned when the request is accepted by a node that can sign and broadcast transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "unknown account"
  }
}
```

## Recommended workflow

1. Build the raw transaction locally with your wallet or SDK.
2. Sign the payload client-side (hardware wallet, custodial service, or library).
3. Submit the signed hex string with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/centrifuge/eth_sendRawTransaction).

## Example response from the shared endpoint

```bash
curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0x0000000000000000000000000000000000000000"}],"id":1}'
```

```json
{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"unknown account"}}
```

Need help? Contact our [support team](mailto:support@dwellir.com) or use the dedicated [`eth_sendRawTransaction`](https://www.dwellir.com/docs/centrifuge/eth_sendRawTransaction) guide.

---

## eth_signTransaction - Sign transaction (r...

# eth_signTransaction - Sign transaction (r...

Signs a transaction using an unlocked account on the node. **Important**: Most RPC providers don't support this method for security reasons, as it requires private keys to be stored on the server.

## Security Considerations

- This method requires an unlocked account on the node
- Private keys must be available to the RPC server
- Most production RPC providers disable this method
- Use client-side signing libraries instead for better security

## Request Parameters

This method accepts no parameters.

## Request Example

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'eth_signTransaction',
        params: [{
          from: '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83',
          to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
          gas: '0x76c0',
          gasPrice: '0x9184e72a000',
          value: '0x9184e72a'
        }],
        id: 1
      })
    });

    const data = await response.json();
    console.log(data.result);
```

## Response Fields

- `result` (`OBJECT, required`): `DATA` - The signed transaction data, ready for transmission via `eth_sendRawTransaction`.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xf86c808504a817c8008276c094d46e8dd67c5d32be8058bb8eb970870f072445675849184e72a8001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
```

## Implementation Example

`eth_signTransaction` requires access to an unlocked account, which Dwellir's shared RPC endpoints do not provide. Sign the payload locally (wallet, HSM, or KMS) and then broadcast with `eth_sendRawTransaction`.

JavaScript

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_signTransaction',
    params: [{
      from: '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83',
      to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_syncing - Check node sync status

# eth_syncing - Check node sync status

Check node sync status on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_syncing",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_syncing',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_uninstallFilter - Uninstall Filter

# eth_uninstallFilter - Uninstall Filter

Remove filter subscription on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Create a short-lived filter so we have an ID to remove (requires jq)
    FILTER_ID=$(curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newFilter",
        "params": [{
          "fromBlock": "latest",
          "toBlock": "latest",
          "address": null,
          "topics": []
        }],
        "id": 1
      }' | jq -r '.result')

    # Uninstall the filter and confirm the response
    curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d "$(jq -n --arg id \"$FILTER_ID\" '{jsonrpc:\"2.0\", method:\"eth_uninstallFilter\", params:[$id], id:1}')"
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
# Create a short-lived filter so we have an ID to remove (requires jq)
FILTER_ID=$(curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": null,
      "topics": []
    }],
    "id": 1
  }' | jq -r '.result')

# Uninstall the filter and confirm the response
curl -s -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg id \"$FILTER_ID\" '{jsonrpc:\"2.0\", method:\"eth_uninstallFilter\", params:[$id], id:1}')"
```

```javascript
const endpoint = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY';

const createFilter = async () => {
  const payload = {
    jsonrpc: '2.0',
    method: 'eth_newFilter',
    params: [{ fromBlock: 'latest', toBlock: 'latest', address: null, topics: [] }],
    id: 1
  };

  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });

  const { result } = await response.json();
  return result;
};

const filterId = await createFilter();
const response = await fetch(endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_uninstallFilter',
    params: [filterId],
    id: 2
  })
});

const data = await response.json();
console.log(data.result);
```

---

## grandpa_roundState - Centrifuge RPC Method

# grandpa_roundState - Centrifuge RPC Method

Returns the state of the current GRANDPA finality round on Centrifuge when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`grandpa_roundState` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Centrifuge, critical for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/centrifuge/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/centrifuge/system_health) -- Check overall node health including sync and peer status

---

## net_listening - Check if node is listening

# net_listening - Check if node is listening

Check if node is listening on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "net_listening",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## net_peerCount - Get connected peer count

# net_peerCount - Get connected peer count

Get connected peer count on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "net_peerCount",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## net_version - Get network ID

# net_version - Get network ID

Get network ID on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "net_version",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## payment_queryFeeDetails - Centrifuge RPC Method

# payment_queryFeeDetails - Centrifuge RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Centrifuge. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`payment_queryFeeDetails` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Centrifuge
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/centrifuge/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/centrifuge/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Centrifuge RPC Method

# payment_queryInfo - Centrifuge RPC Method

Estimates the fee for an encoded extrinsic on Centrifuge. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`payment_queryInfo` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Centrifuge
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/centrifuge/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/centrifuge/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/centrifuge/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Centrifuge RPC Method

# rpc_methods - Centrifuge RPC Method

Returns a list of all RPC methods exposed by the Centrifuge node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`rpc_methods` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Centrifuge node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Centrifuge endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Centrifuge endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/centrifuge/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/centrifuge/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Centrifuge RPC Method

# state_call - Centrifuge RPC Method

Calls a runtime API function on Centrifuge and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`state_call` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/centrifuge/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/centrifuge/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/centrifuge/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-centrifuge.n.dwellir.com"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-centrifuge.n.dwellir.com', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-centrifuge.n.dwellir.com') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/centrifuge/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/centrifuge/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - Centrifuge RPC Method

# state_getKeysPaged - Centrifuge RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Centrifuge. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`state_getKeysPaged` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Centrifuge
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-centrifuge.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/centrifuge/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/centrifuge/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Centrifuge RPC Method

# state_getMetadata - Centrifuge RPC Method

Returns the runtime metadata for Centrifuge as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`state_getMetadata` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Centrifuge
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Centrifuge:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Centrifuge:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/centrifuge/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/centrifuge/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Centrifuge RPC Method

# state_getRuntimeVersion - Centrifuge RPC Method

Returns the runtime version information for Centrifuge, including the spec name, spec version, implementation version, and supported API versions.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`state_getRuntimeVersion` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Centrifuge
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Centrifuge in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/centrifuge/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Centrifuge RPC Method

# state_getStorage - Centrifuge RPC Method

Returns the SCALE-encoded storage value for a given key on Centrifuge. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`state_getStorage` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Centrifuge
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/centrifuge/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/centrifuge/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Centrifuge RPC Method

# state_queryStorageAt - Centrifuge RPC Method

Queries multiple storage keys at a specific block on Centrifuge, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`state_queryStorageAt` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Centrifuge
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/centrifuge/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/centrifuge/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/centrifuge/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/centrifuge/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Centrifuge RPC Method

# system_chain - Centrifuge RPC Method

Returns the chain name of the Centrifuge network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`system_chain` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Network Verification** -- Confirm your application is connected to the correct Centrifuge network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Centrifuge"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', 'Centrifuge');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/centrifuge/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/centrifuge/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/centrifuge/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/centrifuge/rpc_methods) -- List all available RPC methods

---

## system_health - Centrifuge RPC Method

# system_health - Centrifuge RPC Method

Returns the health status of the Centrifuge node, including peer count, sync state, and whether the node expects to have peers.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`system_health` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Centrifuge
- **Load Balancing** - Route requests only to healthy, fully synced nodes for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Centrifuge:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Centrifuge nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/centrifuge/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Centrifuge RPC Method

# system_name - Centrifuge RPC Method

Returns the node implementation name on Centrifuge. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`system_name` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Centrifuge
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Centrifuge node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Centrifuge node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Centrifuge node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Centrifuge node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Centrifuge node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Centrifuge nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/centrifuge/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/centrifuge/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/centrifuge/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/centrifuge/rpc_methods) -- List all available RPC methods

---

## system_properties - Centrifuge RPC Method

# system_properties - Centrifuge RPC Method

Returns the chain-specific properties for Centrifuge, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`system_properties` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Centrifuge
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/centrifuge/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/centrifuge/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/centrifuge/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/centrifuge/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/centrifuge/rpc_methods) -- List all available RPC methods

---

## system_version - Centrifuge RPC Method

# system_version - Centrifuge RPC Method

Returns the node implementation version string on Centrifuge. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`system_version` is essential for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Centrifuge
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Centrifuge node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Centrifuge node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-centrifuge.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Centrifuge node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-centrifuge.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Centrifuge node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-centrifuge.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Centrifuge node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Centrifuge nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/centrifuge/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/centrifuge/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/centrifuge/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/centrifuge/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/centrifuge/rpc_methods) -- List all available RPC methods

---

## web3_clientVersion - Get client version

# web3_clientVersion - Get client version

Get client version on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "web3_clientVersion",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## web3_sha3 - Calculate Keccak-256 Hash on...

# web3_sha3 - Calculate Keccak-256 Hash on...

Calculate Keccak-256 hash on the Centrifuge network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "web3_sha3",
        "params": ["0x68656c6c6f20776f726c64"],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-centrifuge.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f20776f726c64"],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-centrifuge.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_sha3',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## Chiliz RPC with Dwellir

# Chiliz RPC with Dwellir

## Chiliz RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Chiliz supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Chiliz?

Chiliz is the leading blockchain for sports and entertainment, designed to power the $50 billion sports fan engagement market. Built as an Ethereum-compatible network, Chiliz offers:

### **Sports-First Ecosystem**

- **Fan Tokens native support** - Industry-leading fan engagement infrastructure
- **2M+ active sports fans** - Direct access to the world's largest web3 sports community
- **100+ sports partnerships** - Major clubs and organizations already integrated

### **High Performance EVM**

- **Fast finality** - Optimized consensus for real-time fan interactions
- **Low transaction costs** - Affordable microtransactions for fan engagement
- **EVM compatibility** - Full Ethereum tooling and contract support

### **Proven Infrastructure**

- **Battle-tested platform** - Powering millions of fan interactions since 2019
- **Enterprise-grade security** - Institutional infrastructure for major sports brands
- **Scalable architecture** - Built to handle massive fan engagement events

## Quick Start with Chiliz

Connect to Chiliz in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Chiliz mainnet
const provider = new JsonRpcProvider(
  'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Chiliz mainnet
const web3 = new Web3(
  'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Chiliz:', chainId === 88888);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http, defineChain } from 'viem';

const chiliz = defineChain({
  id: 88888,
  name: 'Chiliz',
  nativeCurrency: {
    decimals: 18,
    name: 'CHZ',
    symbol: 'CHZ',
  },
  rpcUrls: {
    default: {
      http: ['https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'],
    },
  },
  blockExplorers: {
    default: { name: 'ChilizScan', url: 'https://chiliscan.com' },
  },
});

// Create Chiliz client
const client = createPublicClient({
  chain: chiliz,
  transport: http('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to Chiliz mainnet
w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Verify connection and get chain ID
assert w3.is_connected()
chain_id = w3.eth.chain_id
print(f'Connected to Chiliz: {chain_id == 88888}')

# Get latest block number
block_number = w3.eth.block_number
print(f'Latest block: {block_number}')
```

## Network Information

| Parameter        | Value    | Details       |
| ---------------- | -------- | ------------- |
| Chain ID         | 88888    | Mainnet       |
| Testnet Chain ID | 88882    | Spicy Testnet |
| Gas Token        | CHZ      | Native token  |
| RPC Standard     | Ethereum | JSON-RPC 2.0  |

## API Reference

Chiliz supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods for seamless EVM integration.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Log transaction success
  console.log('Transaction confirmed:', receipt.transactionHash);
  console.log('Gas used:', receipt.gasUsed.toString());

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Chiliz:

```javascript
// Estimate gas for optimal transaction pricing
const gasEstimate = await provider.estimateGas(tx);

// Get current gas price
const gasPrice = await provider.getGasPrice();

// Calculate total transaction cost
const totalCost = gasEstimate * gasPrice;
console.log('Estimated cost:', totalCost.toString(), 'CHZ');
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with pagination for large datasets
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 5000; // Chiliz recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class ChilizProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Wrong Chain ID"

Ensure you're using the correct chain ID for Chiliz:

```javascript
// Verify chain connection
const network = await provider.getNetwork();
console.log('Connected to chain ID:', network.chainId);

// Mainnet should return 88888 (0x15b38 in hex)
// Testnet should return 88882 (0x15b32 in hex)
```

### Error: "Insufficient funds for gas"

CHZ is required for all transactions on Chiliz:

```javascript
// Check CHZ balance before transaction
const balance = await provider.getBalance(address);
const gasPrice = await provider.getGasPrice();
const gasEstimate = await provider.estimateGas(tx);
const requiredGas = gasPrice * gasEstimate;

if (balance < requiredGas + tx.value) {
  throw new Error(`Need ${(requiredGas + tx.value - balance).toString()} more CHZ`);
}
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## FAQs

### What makes Chiliz different from other EVM chains?

Chiliz is purpose-built for sports and entertainment, offering native Fan Token infrastructure and direct access to millions of sports fans worldwide.

### Can I use existing Ethereum tools with Chiliz?

Yes! Chiliz is fully EVM-compatible, so all Ethereum tools, libraries, and smart contracts work seamlessly.

### What's the native token on Chiliz?

CHZ is the native gas token used for all transactions on Chiliz Chain.

### How do I get CHZ for testing?

Use the Spicy Testnet with testnet CHZ from official faucets, or contact Dwellir support for testing assistance.

## Smoke Tests

### Test Mainnet Connection

```bash
# Test mainnet connectivity
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Test Testnet Connection

```bash
# Test Spicy testnet connectivity
curl -X POST https://api-chiliz-spicy.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Ethers.js Chain Verification

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Verify connection and chain ID
const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId); // Should be 88888
console.log('Block number:', await provider.getBlockNumber());
```

### web3.py Connection Test

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Verify connection
assert w3.is_connected(), "Failed to connect to Chiliz"
print(f"Chain ID: {w3.eth.chain_id}") # Should be 88888
print(f"Latest block: {w3.eth.block_number}")
```

## Migration Guide

### From Ethereum Mainnet

Moving from Ethereum to Chiliz requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Chiliz)
const provider = new JsonRpcProvider(
  'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Standard EVM opcodes
// Note: Different chain ID (88888)
// Note: CHZ as gas token instead of ETH
// Note: Sports-focused ecosystem
```

## Resources & Tools

### Official Resources

- [Chiliz Documentation](https://docs.chiliz.com)
- [Chiliz Explorer](https://scan.chiliz.com)
- [Spicy Testnet Explorer](https://spicy-explorer.chiliz.com)

### Sports Ecosystem

- [Socios.com](https://socios.com) - Fan Token platform
- [Fan Token Directory](https://www.chiliz.com/fan-tokens) - Available fan tokens
- [Chiliz Ecosystem](https://greenhousehub.chiliz.com/) - Web3 projects on Chiliz Chain

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Chiliz with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Chiliz RPC Method

# debug_traceBlock - Chiliz RPC Method

Traces all transactions in a block on Chiliz by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Chiliz - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for sports organizations, entertainment brands, and fan engagement platform developers:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Chiliz
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Chiliz:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Chiliz blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/chiliz/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/chiliz/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Chiliz RPC Method

# debug_traceBlockByHash - Chiliz RPC Method

Traces all transactions in a block on Chiliz identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Chiliz - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Chiliz
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Chiliz:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Chiliz:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

z |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32002 | Resource unavailable | Node is syncing or the requested block is not yet available |

```javascript
async function safeTraceBlockByHash(provider, blockHash, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByHash', [blockHash, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByHash not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockHash} not found - verify the hash is correct`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByHash', [
        blockHash,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/chiliz/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/chiliz/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/chiliz/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/chiliz/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Chiliz RPC Method

# debug_traceBlockByNumber - Chiliz RPC Method

Traces all transactions in a block on Chiliz identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Chiliz - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Chiliz execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Chiliz:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Chiliz:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

z - it may be in the future |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32602 | Invalid params | Check that the block number is a valid hex string or tag |

```javascript
async function safeTraceBlockByNumber(provider, blockNumber, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByNumber', [blockNumber, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByNumber not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockNumber} not found on Chiliz`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByNumber', [
        blockNumber,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/chiliz/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/chiliz/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/chiliz/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Chiliz RPC Method

# debug_traceCall - Chiliz RPC Method

Traces a call on Chiliz without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Chiliz - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for sports organizations, entertainment brands, and fan engagement platform developers:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Chiliz
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "data": "0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
        "data": "0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
        "data": "0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    data: '0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    data: '0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    'data': '0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
        "data": "0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Chiliz to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Chiliz:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Chiliz:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/chiliz/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/chiliz/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Chiliz RPC Method

# debug_traceTransaction - Chiliz RPC Method

Traces a transaction execution on Chiliz by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Chiliz
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/chiliz/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/chiliz/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Chiliz RPC Method

# eth_accounts - Chiliz RPC Method

Returns a list of addresses owned by the client on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for sports organizations, entertainment brands, and fan engagement platform developers in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/chiliz/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/chiliz/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Chiliz RPC Method

# eth_blockNumber - Chiliz RPC Method

Returns the number of the most recent block on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_blockNumber` is fundamental for sports organizations, entertainment brands, and fan engagement platform developers:

- **Syncing Applications** - Keep your dApp in sync with the latest Chiliz blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Chiliz block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Chiliz block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Chiliz block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Chiliz block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chiliz block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Chiliz:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Chiliz:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Chiliz node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/chiliz/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/chiliz/eth_syncing) - Check if node is still syncing

---

## eth_call - Chiliz RPC Method

# eth_call - Chiliz RPC Method

Executes a new message call immediately without creating a transaction on Chiliz. Used for reading smart contract state.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

The `eth_call` method serves these key scenarios for sports organizations, entertainment brands, and fan engagement platform developers:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Chiliz
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';
const walletAddress = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Chiliz. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Chiliz
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Chiliz

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "data": "0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "data": "0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    data := common.FromHex("0x70a08231000000000000000000000000721EF6871f1c4Efe730dCE047d40D1743B886946")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Chiliz RPC Method

# eth_chainId - Chiliz RPC Method

Returns the chain ID used for transaction signing on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_chainId` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/chiliz/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/chiliz/eth_syncing) - Check sync status

---

## eth_coinbase - Chiliz RPC Method

# eth_coinbase - Chiliz RPC Method

Checks the legacy `eth_coinbase` compatibility method on Chiliz. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for sports organizations, entertainment brands, and fan engagement platform developers when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Chiliz coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Chiliz coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Chiliz coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Chiliz coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Chiliz coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Chiliz nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/chiliz/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/chiliz/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/chiliz/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Chiliz RPC Method

# eth_estimateGas - Chiliz RPC Method

Estimates the gas necessary to execute a transaction on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for sports organizations, entertainment brands, and fan engagement platform developers:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Chiliz
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x721EF6871f1c4Efe730dCE047d40D1743B886946', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x721EF6871f1c4Efe730dCE047d40D1743B886946', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Chiliz.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Chiliz may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "to": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x721EF6871f1c4Efe730dCE047d40D1743B886946', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/chiliz/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Chiliz RPC Method

# eth_feeHistory - Chiliz RPC Method

Returns historical gas fee data on Chiliz, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for sports organizations, entertainment brands, and fan engagement platform developers:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Chiliz without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Chiliz.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Chiliz) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/chiliz/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/chiliz/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Chiliz RPC Method

# eth_gasPrice - Chiliz RPC Method

Returns the current gas price on Chiliz in wei.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for sports organizations, entertainment brands, and fan engagement platform developers:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Chiliz
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Chiliz. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Chiliz, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Chiliz: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Chiliz supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/chiliz/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/chiliz/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Chiliz RPC Method

# eth_getBalance - Chiliz RPC Method

Returns the balance of a given address on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getBalance` is fundamental for sports organizations, entertainment brands, and fan engagement platform developers:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Chiliz
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Chiliz
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Chiliz. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Chiliz`);
  return balance;
}

displayBalance('0x721EF6871f1c4Efe730dCE047d40D1743B886946');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Chiliz at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Chiliz')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Chiliz')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Chiliz.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/chiliz/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/chiliz/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Chiliz RPC Method

# eth_getBlockByHash - Chiliz RPC Method

Returns information about a block by hash on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getBlockByHash` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Chiliz
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Chiliz.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Chiliz.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Chiliz RPC Method

# eth_getBlockByNumber - Chiliz RPC Method

Returns information about a block by block number on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getBlockByNumber` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Chiliz
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Chiliz with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Chiliz. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/chiliz/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/chiliz/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Chiliz RPC Method

# eth_getBlockReceipts - Chiliz RPC Method

Returns all transaction receipts for a block on Chiliz. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getBlockReceipts` is useful for sports organizations, entertainment brands, and fan engagement platform developers:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Chiliz, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Chiliz. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xa9922ade53a153685d0ee94acdaf34dacc756b4a0170812abd7338daca98c178",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/chiliz/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/chiliz/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Chiliz RPC Method

# eth_getCode - Chiliz RPC Method

Returns the bytecode at a given address on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getCode` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Chiliz
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Chiliz:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Chiliz:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/chiliz/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/chiliz/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Chiliz RPC Method

# eth_getFilterChanges - Chiliz RPC Method

Polls a filter on Chiliz for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getFilterChanges` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Chiliz
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Chiliz:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/chiliz/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/chiliz/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/chiliz/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/chiliz/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/chiliz/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Chiliz RPC Method

# eth_getFilterLogs - Chiliz RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Chiliz. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getFilterLogs` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Chiliz
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x721EF6871f1c4Efe730dCE047d40D1743B886946"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/chiliz/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/chiliz/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/chiliz/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/chiliz/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Chiliz RPC Method

# eth_getLogs - Chiliz RPC Method

Returns an array of all logs matching a given filter object on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for sports organizations, entertainment brands, and fan engagement platform developers:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Chiliz for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Chiliz
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Chiliz.

```javascript
const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Chiliz enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Chiliz, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/chiliz/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/chiliz/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Chiliz RPC Method

# eth_getStorageAt - Chiliz RPC Method

Returns the value from a storage position at a given address on Chiliz. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getStorageAt` is essential for sports organizations, entertainment brands, and fan engagement platform 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 sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **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": [
    "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "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-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x721EF6871f1c4Efe730dCE047d40D1743B886946', '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-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';

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-chiliz-mainnet-archive.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 = '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
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-chiliz-mainnet-archive.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-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    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 Chiliz:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.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-chiliz-mainnet-archive.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 = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';
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 Chiliz:`);
  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/chiliz/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/chiliz/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/chiliz/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Chiliz RPC Method

# eth_getTransactionByHash - Chiliz RPC Method

Returns the information about a transaction by transaction hash on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getTransactionByHash` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Chiliz
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Chiliz. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Chiliz. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/chiliz/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Chiliz RPC Method

# eth_getTransactionCount - Chiliz RPC Method

Returns the number of transactions sent from an address on Chiliz, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getTransactionCount` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Chiliz
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x721EF6871f1c4Efe730dCE047d40D1743B886946', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Chiliz nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x721EF6871f1c4Efe730dCE047d40D1743B886946'
nonce = get_transaction_count(address)
print(f'Chiliz nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Chiliz nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Chiliz:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x721EF6871f1c4Efe730dCE047d40D1743B886946');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/chiliz/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/chiliz/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/chiliz/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Chiliz RPC Method

# eth_getTransactionReceipt - Chiliz RPC Method

Returns the receipt of a transaction by transaction hash on Chiliz. Receipt is only available for mined transactions.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_getTransactionReceipt` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Chiliz and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Chiliz. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Chiliz, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x01038cb6fa5140b5068293ecaf6e2029eae653b9489388ff252e1c18b4606f39")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/chiliz/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/chiliz/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Chiliz RPC Method

# eth_hashrate - Chiliz RPC Method

Returns the legacy `eth_hashrate` compatibility value on Chiliz. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for sports organizations, entertainment brands, and fan engagement platform developers:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Chiliz hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Chiliz hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Chiliz hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Chiliz hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Chiliz hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/chiliz/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/chiliz/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Chiliz RPC Method

# eth_maxPriorityFeePerGas - Chiliz RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Chiliz. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Chiliz
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Chiliz priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Chiliz priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Chiliz priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Chiliz:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Chiliz:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/chiliz/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/chiliz/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/chiliz/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Chiliz RPC Method

# eth_mining - Chiliz RPC Method

Checks the legacy `eth_mining` compatibility method on Chiliz. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for sports organizations, entertainment brands, and fan engagement platform developers:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Chiliz mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Chiliz mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Chiliz mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Chiliz mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Chiliz mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/chiliz/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/chiliz/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Chiliz RPC Method

# eth_newBlockFilter - Chiliz RPC Method

Creates a filter on Chiliz that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_newBlockFilter` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Block Monitoring** - Detect new blocks on Chiliz as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Chiliz:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/chiliz/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/chiliz/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/chiliz/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Chiliz RPC Method

# eth_newFilter - Chiliz RPC Method

Creates a filter object on Chiliz based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_newFilter` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Event Monitoring** - Subscribe to specific contract events on Chiliz such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x721EF6871f1c4Efe730dCE047d40D1743B886946",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Chiliz:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x721EF6871f1c4Efe730dCE047d40D1743B886946',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/chiliz/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/chiliz/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/chiliz/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/chiliz/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/chiliz/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Chiliz RPC Method

# eth_newPendingTransactionFilter - Chiliz RPC Method

Creates a filter on Chiliz that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Mempool Monitoring** - Observe unconfirmed transactions on Chiliz to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for sports fan tokens (Socios.com), club voting rights, gamified fan experiences, and tokenized sports assets

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Chiliz...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Chiliz:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/chiliz/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/chiliz/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/chiliz/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Chiliz RPC Method

# eth_protocolVersion - Chiliz RPC Method

Returns the current Ethereum protocol version used by the Chiliz node.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_protocolVersion` is useful for sports organizations, entertainment brands, and fan engagement platform developers:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Chiliz protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Chiliz protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Chiliz protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Chiliz protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chiliz protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Chiliz nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/chiliz/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/chiliz/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/chiliz/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Chiliz RPC Method

# eth_sendRawTransaction - Chiliz RPC Method

Submits a pre-signed transaction for broadcast to Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for sports organizations, entertainment brands, and fan engagement platform developers:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Chiliz
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x721EF6871f1c4Efe730dCE047d40D1743B886946', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Chiliz mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/chiliz/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x721EF6871f1c4Efe730dCE047d40D1743B886946")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/chiliz/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/chiliz/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Chiliz RPC Method

# eth_sendTransaction - Chiliz RPC Method

Creates and sends a new transaction from an unlocked account on Chiliz. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for sports organizations, entertainment brands, and fan engagement platform developers in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Chiliz tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Chiliz tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Chiliz tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Chiliz tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chiliz tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Chiliz dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/chiliz/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/chiliz/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Chiliz RPC Method

# eth_signTransaction - Chiliz RPC Method

Signs a transaction with the private key of the specified account on Chiliz without submitting it to the network.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for sports organizations, entertainment brands, and fan engagement platform developers in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Chiliz tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Chiliz tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Chiliz tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Chiliz:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/chiliz/eth_accounts) - List accounts available for signing

---

## eth_syncing - Chiliz RPC Method

# eth_syncing - Chiliz RPC Method

Returns the sync status of your Chiliz node - either `false` when fully synced, or an object describing the sync progress.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_syncing` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Chiliz node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Chiliz node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Chiliz node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/chiliz/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/chiliz/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/chiliz/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Chiliz RPC Method

# eth_uninstallFilter - Chiliz RPC Method

Removes a filter on Chiliz that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`eth_uninstallFilter` is important for sports organizations, entertainment brands, and fan engagement platform developers:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/chiliz/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/chiliz/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/chiliz/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/chiliz/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/chiliz/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Chiliz RPC Method

# net_listening - Chiliz RPC Method

Checks whether the connected Chiliz client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`net_listening` is useful for sports organizations, entertainment brands, and fan engagement platform developers:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Chiliz node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Chiliz node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Chiliz node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/chiliz/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/chiliz/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/chiliz/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/chiliz/web3_clientVersion) - Get node client info

---

## net_peerCount - Chiliz RPC Method

# net_peerCount - Chiliz RPC Method

Returns the number of peers currently connected to your Chiliz node.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`net_peerCount` is important for sports organizations, entertainment brands, and fan engagement platform developers:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Chiliz deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Chiliz peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Chiliz peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Chiliz peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Chiliz nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/chiliz/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/chiliz/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/chiliz/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/chiliz/web3_clientVersion) - Get node client info

---

## net_version - Chiliz RPC Method

# net_version - Chiliz RPC Method

Returns the current network ID on Chiliz as a decimal string. The network ID identifies which network the node is connected to.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`net_version` is essential for sports organizations, entertainment brands, and fan engagement platform developers:

- **Endpoint Identification** - Confirm your application is connected to the expected Chiliz network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Chiliz network ID:', networkId);

// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Chiliz network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chiliz network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/chiliz/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/chiliz/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/chiliz/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/chiliz/eth_syncing) - Check node sync progress

---

## rpc_modules - Chiliz RPC Method

# rpc_modules - Chiliz RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Chiliz endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`rpc_modules` is useful for sports organizations, entertainment brands, and fan engagement platform developers:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/chiliz/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/chiliz/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Chiliz RPC Method

# txpool_content - Chiliz RPC Method

Returns the full pending and queued transaction pool for the connected Chiliz endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`txpool_content` is useful for sports organizations, entertainment brands, and fan engagement platform developers:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/chiliz/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/chiliz/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/chiliz/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Chiliz RPC Method

# txpool_status - Chiliz RPC Method

Returns transaction pool counters for the connected Chiliz endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`txpool_status` is valuable for sports organizations, entertainment brands, and fan engagement platform developers:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/chiliz/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/chiliz/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/chiliz/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Chiliz RPC Method

# web3_clientVersion - Chiliz RPC Method

Returns the current client software version string for your Chiliz node, including the client name, version number, OS, and runtime.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

## When to Use This Method

`web3_clientVersion` is valuable for sports organizations, entertainment brands, and fan engagement platform developers:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Chiliz client:', clientVersion);

// Using fetch
const response = await fetch('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Chiliz client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chiliz client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/chiliz/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/chiliz/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/chiliz/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/chiliz/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Chiliz RPC Method

# web3_sha3 - Chiliz RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Chiliz.

> **Why Chiliz?** Build on the sports-first blockchain powering 2M+ fan token wallets and dozens of licensed sports partnerships with licensed partnerships with major football clubs, MiCA-compliant in EU, OG Esports integration, and SportFi DeFi infrastructure.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for sports organizations, entertainment brands, and fan engagement platform developers:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-chiliz-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/chiliz/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/chiliz/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/chiliz/web3_clientVersion) - Get node client version

---

## Dwellir CLI

# Dwellir CLI

The Dwellir CLI (`dwellir`) gives you full access to the Dwellir platform from the command line. Authenticate, manage API keys, discover 150+ blockchain endpoints, monitor usage, and inspect error logs -- all without leaving your terminal.

It is built for three audiences:

- **Developers** who prefer terminal workflows over a web dashboard
- **CI/CD pipelines** that need to provision and rotate API keys automatically
- **AI agents** that consume structured TOON/JSON output

## Quick start

```bash
# Install
curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh

# Authenticate
dwellir auth login

# List your API keys
dwellir keys list

# Discover Ethereum endpoints
dwellir endpoints search ethereum
```

Also available via [Homebrew, AUR, `go install`, or from source](https://www.dwellir.com/docs/cli/installation).

## Output modes

Every command supports multiple output modes:

- `--human` -- formatted tables and key-value displays (default in interactive terminals)
- `--json` -- JSON wrapped in a standard `{ok, data, meta}` envelope for scripting and automation
- `--toon` -- TOON format (structured text)

In auto-detected non-interactive/agent environments (for example non-TTY runs, Codex, and Claude agent runs), the CLI defaults to TOON when no explicit output config exists.
Use `--json` for strict machine pipelines (especially `jq`-first scripts), or set `dwellir config set output json` to make JSON your default.

```bash
dwellir keys list --json
```

JSON responses use a consistent envelope:

```json
{
  "ok": true,
  "data": { ... },
  "meta": {
    "command": "keys.list",
    "timestamp": "2026-02-26T12:00:00Z"
  }
}
```

Errors return `ok: false` with an error code, message, and optional help text, plus a non-zero exit code.

### Benchmark note (JSON vs TOON for agents)

A local benchmark run (Codex + Claude, 8 total runs) showed:

- Equal correctness (`4/4` pass in both JSON and TOON variants)
- Lower interaction overhead with TOON (`~24%` fewer tool calls)
- Lower output-token footprint with TOON (`~36.5%` fewer output tokens)

Details: [2026-03-03 JSON vs TOON benchmark](https://github.com/dwellir-public/cli/blob/main/docs/benchmarks/2026-03-03-agent-output-mode-json-vs-toon.md)

TOON is not always the right choice. See:

- [When not to use TOON](https://github.com/toon-format/toon/tree/main/packages/toon#when-not-to-use-toon)
- [TOON benchmarks](https://github.com/toon-format/toon/tree/main/packages/toon#benchmarks)

## Command overview

| Command              | Description                                                                                                   |
| -------------------- | ------------------------------------------------------------------------------------------------------------- |
| `dwellir auth`       | Login, logout, check status, print tokens                                                                     |
| `dwellir keys`       | Create, list, update, enable, disable, and delete API keys. Copy a key to the clipboard or write it to `.env` |
| `dwellir endpoints`  | Browse and search 150+ blockchain endpoints                                                                   |
| `dwellir usage`      | View billing-cycle summary, usage by endpoint/method, costs, and RPS                                          |
| `dwellir logs`       | Inspect error logs, stats, and facet aggregations                                                             |
| `dwellir account`    | View organization info and subscription details                                                               |
| `dwellir docs`       | List, search, and fetch Dwellir documentation as markdown                                                     |
| `dwellir config`     | Get and set CLI configuration values                                                                          |
| `dwellir completion` | Generate or install shell completions (bash, zsh, fish, powershell)                                           |
| `dwellir update`     | Self-update to the latest release                                                                             |
| `dwellir version`    | Print build and version metadata                                                                              |

## Global flags

These flags work on every command:

| Flag               | Description                                                         |
| ------------------ | ------------------------------------------------------------------- |
| `--json`           | Output as JSON                                                      |
| `--human`          | Output as human-readable tables (default in interactive terminals)  |
| `--toon`           | Output as TOON format (auto-selected in non-interactive/agent mode) |
| `--profile <name>` | Use a specific auth profile                                         |
| `-q`, `--quiet`    | Suppress non-essential output                                       |
| `--anon-telemetry` | Anonymize telemetry data                                            |

Run `dwellir --help` or `dwellir <command> --help` for full usage details.

## Next steps

- [Installation](https://www.dwellir.com/docs/cli/installation) -- five ways to install the CLI
- [Authentication](https://www.dwellir.com/docs/cli/authentication) -- browser login, CI tokens, and profiles
- [API Keys](https://www.dwellir.com/docs/cli/api-keys) -- create and manage keys
- [Endpoints](https://www.dwellir.com/docs/cli/endpoints) -- discover blockchain networks
- [Usage & Logs](https://www.dwellir.com/docs/cli/usage-and-logs) -- monitor requests and debug errors
- [Configuration](https://www.dwellir.com/docs/cli/configuration) -- profiles, environment variables, and per-project settings
- [Agent Tooling](https://www.dwellir.com/docs/agents) -- migration prompt, agent skills, and documentation endpoints for AI agents

---

## API Key Management

# API Key Management

Use `dwellir keys` to create, list, update, and delete API keys for your Dwellir account.

The CLI never prints a full API key. Every output format shows keys masked, for example `d8d3****eef9`. To use a key, [copy it to the clipboard or write it to `.env`](#use-a-key). This behavior starts in CLI 0.3.0.

The Dwellir CLI cannot create or assign IP whitelists. Use [API key IP whitelisting](https://www.dwellir.com/docs/getting-started/ip-whitelisting) in the dashboard.

## List all keys

```bash
dwellir keys list
```

With JSON output:

```bash
dwellir keys list --json
```

```json
{
  "ok": true,
  "data": [
    {
      "api_key": "d8d3****eef9",
      "name": "production",
      "enabled": true,
      "created_at": "2025-10-14T14:07:24.592946",
      "updated_at": "2025-10-14T14:07:24.592946"
    }
  ],
  "meta": {
    "command": "keys.list",
    "timestamp": "2026-02-26T12:00:00Z"
  }
}
```

The `api_key` field shows the first and last four characters of the key. The masked value does not work as a credential.

The `daily_quota` and `monthly_quota` fields appear only when a quota has been set on the key. Keys without quotas omit these fields (shown as "Unlimited" in human output).

## Select a key

Commands that act on one key take the key name, for example `production`. The masked value from `keys list` and the full key value also work. Names match without regard to case.

If two keys have the same name, the CLI returns an error that lists both masked values. Select one by its masked value, or give each key a unique name.

## Create a key

```bash
dwellir keys create --name my-key
```

Optionally set quotas at creation time:

```bash
dwellir keys create --name ci-key --daily-quota 100000 --monthly-quota 3000000
```

| Flag              | Description                                |
| ----------------- | ------------------------------------------ |
| `--name`          | A descriptive name for the key (required)  |
| `--daily-quota`   | Maximum requests per day (0 = unlimited)   |
| `--monthly-quota` | Maximum requests per month (0 = unlimited) |

The output shows the new key masked. To use it, run `dwellir keys copy my-key` or `dwellir keys env my-key`.

## Use a key

### Copy a key to the clipboard

```bash
dwellir keys copy my-key
```

The CLI sends the key to the clipboard tool on standard input, not as a command argument. It selects the tool for your platform:

| Platform           | Clipboard tool         |
| ------------------ | ---------------------- |
| macOS              | `pbcopy`               |
| Windows and WSL    | `clip.exe`             |
| Linux with Wayland | `wl-copy`              |
| Linux with X11     | `xclip` or `xsel`      |
| Termux             | `termux-clipboard-set` |

On Linux, the display server selects the tool, not the distribution. Over SSH or in CI there is no clipboard. The command then fails with the `clipboard_unavailable` error code. Use `keys env` instead.

### Write a key to `.env`

```bash
dwellir keys env my-key
```

The command writes `DWELLIR_API_KEY='<key>'` to `.env` in the current directory. It does not print the key.

| Flag         | Default           | Description                              |
| ------------ | ----------------- | ---------------------------------------- |
| `--env-file` | `.env`            | Environment file: `.env` or `.env.local` |
| `--var`      | `DWELLIR_API_KEY` | Variable name                            |
| `--replace`  | `false`           | Replace an existing value                |

The CLI applies the same file rules as `dwellir project setup`:

- The file gets mode `0600`.
- The CLI adds an ignore rule for the file to `.gitignore`.
- The CLI refuses a file that Git tracks.
- The CLI refuses to overwrite an existing variable unless you pass `--replace`.

Your application reads `DWELLIR_API_KEY` at runtime. For example, load `.env` into a shell session:

```bash
set -a; . ./.env; set +a
curl -s "https://api-ethereum-mainnet.n.dwellir.com/$DWELLIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

To write the key and the endpoint URLs together, use `dwellir project setup`.

## Update a key

Change the name or quotas of an existing key:

```bash
dwellir keys update my-key --name new-name --daily-quota 50000
```

Only the flags you pass are updated. For example, to change just the daily quota:

```bash
dwellir keys update my-key --daily-quota 200000
```

## Enable and disable a key

Temporarily disable a key without deleting it:

```bash
dwellir keys disable my-key
```

Re-enable it later:

```bash
dwellir keys enable my-key
```

A disabled key returns `403` errors for any API requests made with it.

## Delete a key

Permanently remove an API key:

```bash
dwellir keys delete my-key
```

Deletion is permanent. Any application using this key will immediately lose access. Disable the key first if you want to test the impact.

## Scripting example

Create a temporary key, write it to `.env`, and delete it after the job:

```bash
# Unique per run, so a leftover key from an earlier or parallel run never shares the name
KEY_NAME="ci-$(date +%Y%m%d-%H%M%S)-$$"

# Create the key and write it to .env without printing it
dwellir keys create --name "$KEY_NAME" --daily-quota 50000
dwellir keys env "$KEY_NAME"

# Load DWELLIR_API_KEY into the environment
set -a; . ./.env; set +a

# ... use the key ...

# Clean up
dwellir keys delete "$KEY_NAME"
```

Before CLI 0.3.0, `keys list --json` and `keys create --json` returned the full key in `api_key`. Now that field is masked. Scripts that read `.data.api_key` and send it as a credential fail with an authentication error. Change them to use `keys env` or `project setup`.

## Next steps

- [Discover endpoints](https://www.dwellir.com/docs/cli/endpoints) to use with your keys
- [Monitor usage](https://www.dwellir.com/docs/cli/usage-and-logs) for your keys
- Run `dwellir keys --help` for the full list of flags

---

## Authentication

# Authentication

Authenticate the Dwellir CLI before managing keys, viewing usage, or accessing account data. The method depends on your environment.

## Browser login (interactive)

For local development, open a browser-based login flow:

```bash
dwellir auth login
```

This opens your default browser to the Dwellir dashboard. After you sign in, the CLI receives a token via a local callback and stores it in your profile.

## Token login (headless / CI)

For CI/CD pipelines, Docker containers, or any environment without a browser, pass a token directly:

```bash
dwellir auth login --token <YOUR_CLI_TOKEN>
```

Alternatively, set the token as an environment variable:

```bash
export DWELLIR_TOKEN=<YOUR_CLI_TOKEN>
```

When `DWELLIR_TOKEN` is set, the CLI uses it for every command without needing `dwellir auth login`.

### Getting a CLI token

1. Go to [dashboard.dwellir.com](https://dashboard.dwellir.com)
2. Navigate to **Settings > CLI Tokens** (or the [Agents page](https://dashboard.dwellir.com/agents))
3. Click **Create Token**, give it a name, and copy the value
4. Store the token securely (e.g., as a CI secret)

## Check auth status

See who you are logged in as and which profile is active:

```bash
dwellir auth status
```

```bash
dwellir auth status --json
```

```json
{
  "ok": true,
  "data": {
    "profile": "default",
    "user": "you@example.com",
    "org": "Your Organization"
  }
}
```

The `user` and `org` fields are populated when authenticating via the browser flow. Token-based authentication may return empty values for these fields depending on the token type.

## Print the current token

Print the resolved access token to stdout, useful for piping into other tools:

```bash
dwellir auth token
```

For example, to pass the Dwellir token to another script:

```bash
export TOKEN=$(dwellir auth token)
```

## Logout

Remove local credentials for the active profile:

```bash
dwellir auth logout
```

This deletes the profile file from `~/.config/dwellir/profiles/`. It does not revoke the token on the server.

## Token resolution order

When the CLI needs an auth token, it checks these sources in order:

1. **`DWELLIR_TOKEN`** environment variable
2. **`--token`** flag passed to the command
3. **Profile file** (resolved via the profile resolution chain below)

The first source that provides a non-empty token wins.

## Profile resolution order

When the CLI needs to determine which profile to load, it checks:

1. **`--profile`** flag
2. **`DWELLIR_PROFILE`** environment variable
3. **`.dwellir.json`** file in the current directory or any parent directory
4. **`default_profile`** setting in `~/.config/dwellir/config.json`
5. **`"default"`** as a fallback

## Multiple profiles

You can maintain separate profiles for different accounts or organizations:

```bash
# Login to a "work" profile
dwellir auth login --profile work

# Login to a "personal" profile
dwellir auth login --profile personal

# Use a specific profile for one command
dwellir keys list --profile work
```

### Per-project profile binding

Create a `.dwellir.json` file in your project root to automatically select a profile when you run commands from that directory:

```json
{ "profile": "work" }
```

Now any `dwellir` command run inside that project tree uses the `work` profile without needing the `--profile` flag.

## Next steps

- [Manage API keys](https://www.dwellir.com/docs/cli/api-keys)
- [Discover endpoints](https://www.dwellir.com/docs/cli/endpoints)
- [Configure profiles and defaults](https://www.dwellir.com/docs/cli/configuration)

---

## Configuration

# Configuration

The Dwellir CLI stores configuration and profile data on disk and can be customized via commands, config files, and environment variables.

## Config location

All CLI configuration lives under a single directory:

```
~/.config/dwellir/
  config.json               # Global settings
  profiles/
    default.json            # Default profile (token, user, org)
    work.json               # Additional profiles
```

Override the config directory with `DWELLIR_CONFIG_DIR`:

```bash
export DWELLIR_CONFIG_DIR=/custom/path
```

## Config commands

### Set a value

```bash
dwellir config set <key> <value>
```

Valid keys:

| Key               | Values            | Description                               |
| ----------------- | ----------------- | ----------------------------------------- |
| `output`          | `json` or `human` | Default output format for all commands    |
| `default_profile` | any profile name  | Profile to use when no other is specified |

Examples:

```bash
# Always output JSON by default
dwellir config set output json

# Use the "work" profile by default
dwellir config set default_profile work
```

### Get a value

```bash
dwellir config get output
```

### List all settings

```bash
dwellir config list
```

```bash
dwellir config list --json
```

```json
{
  "ok": true,
  "data": {
    "output": "human",
    "default_profile": "default"
  }
}
```

## Profiles

Profiles store per-account authentication credentials. Each profile is a separate JSON file under `~/.config/dwellir/profiles/`.

Create a profile by logging in with a name:

```bash
dwellir auth login --profile work
dwellir auth login --profile personal
```

Switch profiles per command:

```bash
dwellir keys list --profile work
dwellir keys list --profile personal
```

Or set a default:

```bash
dwellir config set default_profile work
```

### Per-project profile binding

Create a `.dwellir.json` file in any directory to automatically select a profile for that project:

```json
{ "profile": "work" }
```

When you run any `dwellir` command from that directory (or any subdirectory), the CLI automatically uses the `work` profile. This is useful when you work on multiple projects tied to different Dwellir organizations.

The CLI searches for `.dwellir.json` starting from the current directory and walking up to the filesystem root. The first match wins.

## Account info

View your organization and plan details:

```bash
dwellir account info
```

```bash
dwellir account info --json
```

View subscription details:

```bash
dwellir account subscription
```

## Environment variables

Environment variables override config files and flags where noted.

| Variable                 | Description                                                                                                                   |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `DWELLIR_TOKEN`          | Auth token override. Takes highest priority in the [token resolution chain](https://www.dwellir.com/docs/cli/authentication#token-resolution-order). |
| `DWELLIR_PROFILE`        | Profile name override. Takes priority over `.dwellir.json` and `default_profile`.                                             |
| `DWELLIR_CONFIG_DIR`     | Custom config directory (default: `~/.config/dwellir/`)                                                                       |
| `DWELLIR_API_URL`        | Override API base URL (default: `https://dashboard.dwellir.com/marly-api`)                                                    |
| `DWELLIR_DASHBOARD_URL`  | Override dashboard URL for browser auth                                                                                       |
| `DWELLIR_DOCS_BASE_URL`  | Override docs base URL (default: `https://www.dwellir.com/docs`)                                                              |
| `DWELLIR_DOCS_INDEX_URL` | Override docs index URL (default: `<docs-base>/llms.txt`)                                                                     |

### CI/CD example

A minimal GitHub Actions setup using environment variables:

```yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Install Dwellir CLI
        run: curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh

      - name: Create temporary API key
        env:
          DWELLIR_TOKEN: ${{ secrets.DWELLIR_CLI_TOKEN }}
        run: |
          dwellir keys create --name "ci-${{ github.run_id }}" --daily-quota 50000 --json
          dwellir keys env "ci-${{ github.run_id }}"
```

The job log shows the key masked. `keys env` writes the full key to `.env` as `DWELLIR_API_KEY` for later commands in the same job.

## Next steps

- [Authentication](https://www.dwellir.com/docs/cli/authentication) -- token and profile resolution details
- [API Keys](https://www.dwellir.com/docs/cli/api-keys) -- manage keys from the CLI
- Run `dwellir config --help` for the full list of subcommands

---

## Endpoint Discovery

# Endpoint Discovery

Use `dwellir endpoints` to browse and search all available blockchain networks on Dwellir.

## List all endpoints

```bash
dwellir endpoints list
```

This returns every supported chain and network with connection details.

## Search by name

Find endpoints matching a keyword:

```bash
dwellir endpoints search ethereum
```

```bash
dwellir endpoints search polkadot
```

The search matches against chain names and network identifiers.

## Get a specific chain

Retrieve details for a single chain:

```bash
dwellir endpoints get base
```

If no match is found, the CLI returns a helpful error:

```bash
dwellir endpoints get nonexistent --json
```

```json
{
  "ok": false,
  "error": {
    "code": "not_found",
    "message": "No endpoints found for 'nonexistent'.",
    "help": "Run 'dwellir endpoints list' to see all available chains."
  }
}
```

## Filtering

Narrow results using filter flags. These work with `list`, `search`, and `get`:

| Flag          | Example values                                               | Description                                               |
| ------------- | ------------------------------------------------------------ | --------------------------------------------------------- |
| `--ecosystem` | `evm`, `substrate`, `cosmos`, `move`, `hyperliquid`, `other` | Filter by blockchain ecosystem                            |
| `--network`   | `mainnet`, `testnet`, or a specific network name             | Filter by network name (case-insensitive substring match) |
| `--node-type` | `full`, `archive`                                            | Filter by node type (case-insensitive match)              |
| `--protocol`  | `https`, `wss`                                               | Filter by connection protocol                             |

### Examples

List all EVM chains:

```bash
dwellir endpoints list --ecosystem evm
```

Show only mainnet endpoints for Ethereum:

```bash
dwellir endpoints search ethereum --network mainnet
```

List archive nodes in the Substrate ecosystem:

```bash
dwellir endpoints list --ecosystem substrate --node-type archive
```

Combine multiple filters:

```bash
dwellir endpoints list --ecosystem evm --network mainnet --node-type archive
```

## JSON output

Use `--json` to get structured data for scripting:

```bash
dwellir endpoints search ethereum --protocol https --json
```

```json
{
  "ok": true,
  "data": [
    {
      "id": 41,
      "name": "Ethereum",
      "ecosystem": "evm",
      "networks": [
        {
          "id": 43,
          "name": "Mainnet",
          "nodes": [
            {
              "id": 404,
              "https": "https://api-ethereum-mainnet.n.dwellir.com/<key>",
              "wss": "wss://api-ethereum-mainnet.n.dwellir.com/<key>",
              "node_type": { "name": "Archive" }
            }
          ]
        }
      ]
    }
  ],
  "meta": {
    "command": "endpoints.search",
    "timestamp": "2026-02-26T12:00:00Z"
  }
}
```

The response is organized as chains containing networks, each with one or more nodes. Each node includes `https` and `wss` URLs with a `<key>` placeholder.

## Use an endpoint URL with your key

Endpoint output never contains an API key. Replace the `<key>` placeholder at runtime with the key from your environment:

```bash
# Write the key to .env as DWELLIR_API_KEY
dwellir keys env my-key

# Load it and build the URL
set -a; . ./.env; set +a
URL="https://api-ethereum-mainnet.n.dwellir.com/<key>"
curl -s "${URL/<key>/$DWELLIR_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

To write the key and full endpoint URLs to `.env` in one step, run `dwellir project setup --chain ethereum --network mainnet --key-name my-key`. It writes `DWELLIR_API_KEY`, `DWELLIR_RPC_URL`, and `DWELLIR_WSS_URL`.

CLI 0.3.0 removed the `--key` flag from `endpoints list`, `search`, and `get`. The flag now fails with a `validation_error`. Use `keys env` or `project setup` instead.

## Next steps

- [Create an API key](https://www.dwellir.com/docs/cli/api-keys) to use with discovered endpoints
- [Monitor usage](https://www.dwellir.com/docs/cli/usage-and-logs) across your endpoints
- See the full [Supported Chains](https://www.dwellir.com/docs/getting-started/supported-chains) list for network-specific documentation
- Run `dwellir endpoints --help` for the full list of flags

---

## Installation

# Installation

There are five ways to install the Dwellir CLI. Pick whichever suits your environment.

## Homebrew (macOS and Linux)

The recommended method for most users:

```bash
brew tap dwellir-public/homebrew-tap
brew install dwellir
```

To upgrade later:

```bash
brew update && brew upgrade dwellir
```

## AUR (Arch Linux)

If you are on Arch Linux, install from the AUR using your preferred helper:

```bash
yay -S dwellir-cli-bin
```

## Install script

Download and run the latest release installer:

```bash
curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh
```

This detects your OS and architecture, downloads the correct binary from GitHub Releases, and places it in a directory on your `PATH`.

## Go install

If you have Go 1.24+ installed:

```bash
go install github.com/dwellir-public/cli/cmd/dwellir@latest
```

Go places the binary in `$GOPATH/bin` (or `$GOBIN`). Make sure that directory is on your `PATH`.

## Build from source

```bash
git clone https://github.com/dwellir-public/cli.git
cd cli
make build
```

The build outputs `./bin/dwellir`. Move it somewhere on your `PATH`, or run it directly.

## Verify installation

Confirm the CLI is installed and working:

```bash
dwellir version
```

Example output:

```
 Arch        amd64
 Build Date  2026-02-27T12:50:44Z
 Commit      ca1b849
 Go Version  go1.24.13
 Os          linux
 Version     0.1.14
```

Use `--json` for machine-readable output:

```bash
dwellir version --json
```

## Self-update

After installation, you can update to the latest release from within the CLI itself:

```bash
dwellir update
```

This checks GitHub Releases and replaces the running binary in place. If you installed via Homebrew, prefer `brew upgrade dwellir` instead to keep Homebrew's records consistent.

## Next steps

Once installed, [authenticate](https://www.dwellir.com/docs/cli/authentication) to start using the CLI.

---

## Usage & Logs

# Usage & Logs

The Dwellir CLI provides two command groups for monitoring your API activity: `dwellir usage` for request analytics and `dwellir logs` for error inspection.

Usage and log output shows API keys masked, for example `d8d3****eef9`. The `--api-key` and `--key` filters take a key name, the masked value, or the full value. A full value that matches no current key still filters, so you can query usage of a deleted key.

## Usage

### Billing cycle summary

View your total requests for the current billing cycle:

```bash
dwellir usage summary
```

```bash
dwellir usage summary --json
```

### Usage history

View request counts grouped by endpoint:

```bash
dwellir usage history
```

| Flag         | Default                | Description                                      |
| ------------ | ---------------------- | ------------------------------------------------ |
| `--interval` | `hour`                 | Aggregation interval: `minute`, `hour`, or `day` |
| `--from`     | start of billing cycle | Start time in RFC 3339 format                    |
| `--to`       | now                    | End time in RFC 3339 format                      |
| `--api-key`  |                        | Filter by API key name or value                  |
| `--fqdn`     |                        | Filter by endpoint hostname (FQDN)               |
| `--method`   |                        | Filter by RPC method                             |

Examples:

```bash
# Daily usage grouped by endpoint
dwellir usage history --interval day --from 2026-02-19T00:00:00Z

# Filter to a specific endpoint
dwellir usage history --fqdn api-ethereum-mainnet.n.dwellir.com --interval day

# Filter by RPC method
dwellir usage history --method eth_call --from 2026-02-01T00:00:00Z

# Filter by API key name
dwellir usage history --api-key production --interval day
```

### Usage by RPC method

View request counts grouped by RPC method:

```bash
dwellir usage methods
```

| Flag         | Default                | Description                                      |
| ------------ | ---------------------- | ------------------------------------------------ |
| `--interval` | `hour`                 | Aggregation interval: `minute`, `hour`, or `day` |
| `--from`     | start of billing cycle | Start time in RFC 3339 format                    |
| `--to`       | now                    | End time in RFC 3339 format                      |
| `--api-key`  |                        | Filter by API key name or value                  |
| `--fqdn`     |                        | Filter by endpoint hostname (FQDN)               |

### Requests per second

View RPS over time across all endpoints:

```bash
dwellir usage rps
```

| Flag         | Default       | Description                                      |
| ------------ | ------------- | ------------------------------------------------ |
| `--interval` | `hour`        | Aggregation interval: `minute`, `hour`, or `day` |
| `--from`     | past 24 hours | Start time in RFC 3339 format                    |
| `--to`       | now           | End time in RFC 3339 format                      |
| `--api-key`  |               | Filter by API key name or value                  |
| `--fqdn`     |               | Filter by endpoint hostname (FQDN)               |

```bash
dwellir usage rps --json
```

### Estimated costs

View estimated cost breakdown for a usage window (requires Developer plan or higher):

```bash
dwellir usage costs
```

| Flag         | Default                | Description                                      |
| ------------ | ---------------------- | ------------------------------------------------ |
| `--interval` | `hour`                 | Aggregation interval: `minute`, `hour`, or `day` |
| `--from`     | start of billing cycle | Start time in RFC 3339 format                    |
| `--to`       | now                    | End time in RFC 3339 format                      |
| `--api-key`  |                        | Filter by API key name or value                  |
| `--fqdn`     |                        | Filter by endpoint hostname (FQDN)               |
| `--method`   |                        | Filter by RPC method                             |

### Usage query limits

Check your plan's usage query limits (max lookback, supported intervals):

```bash
dwellir usage limits
```

```bash
dwellir usage limits --json
```

## Logs

### Error logs

List recent error responses with optional filters:

```bash
dwellir logs errors
```

| Flag            | Description                     |
| --------------- | ------------------------------- |
| `--key`         | Filter by API key name or value |
| `--endpoint`    | Filter by endpoint FQDN         |
| `--status-code` | Filter by HTTP status code      |
| `--rpc-method`  | Filter by RPC method name       |
| `--from`        | Start time (RFC 3339)           |
| `--to`          | End time (RFC 3339)             |
| `--limit`       | Maximum results (default: 50)   |
| `--cursor`      | Pagination cursor for next page |

Examples:

```bash
# Show rate-limit errors
dwellir logs errors --status-code 429

# Errors for a specific key in the last hour
dwellir logs errors --key production --from 2026-02-26T11:00:00Z

# Filter by RPC method
dwellir logs errors --rpc-method eth_call --limit 20

# Combine filters
dwellir logs errors --endpoint api-ethereum-mainnet.n.dwellir.com --status-code 500 --limit 100
```

### Error stats

View error counts grouped by status code:

```bash
dwellir logs stats
```

Filter the same way as `errors`:

```bash
dwellir logs stats --key production --from 2026-02-20T00:00:00Z
```

### Error facets

Get aggregated breakdowns of error activity across four dimensions:

```bash
dwellir logs facets
```

The output is grouped into four sections:

- **FQDNs** -- which endpoints see the most errors
- **RPC Methods** -- which methods generate the most errors
- **Origins** -- traffic origin breakdown (e.g., `backend` vs `gateway`)
- **API Keys** -- error counts per key, with each key masked and its name

```bash
dwellir logs facets --from 2026-02-01T00:00:00Z --to 2026-02-28T00:00:00Z --json
```

This is useful for identifying which endpoints or methods generate the most errors.

Rows from `logs errors` include `api_key` (masked) and `api_key_name`. Entries in the `api_keys` facet include `value` (masked) and `name`. The CLI gets the names from `keys list`. If that request fails, the output still shows the masked keys without names.

## Pagination

The `logs errors` command supports cursor-based pagination. When more results are available, the response includes a cursor in the metadata:

```bash
# Get the first page
dwellir logs errors --limit 50 --json

# Use the cursor from the response to get the next page
dwellir logs errors --limit 50 --cursor <cursor-from-previous-response> --json
```

## Next steps

- [Manage API keys](https://www.dwellir.com/docs/cli/api-keys) to adjust quotas when you see rate-limit errors
- [Discover endpoints](https://www.dwellir.com/docs/cli/endpoints) to check available networks
- Run `dwellir usage --help` or `dwellir logs --help` for the full list of flags

---

## Cronos, EVM Chain for the Crypto.com Ecosystem

# Cronos, EVM Chain for the Crypto.com Ecosystem

## Cronos RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Cronos supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Cronos?

Cronos is an EVM-compatible Layer 1 built with the Cosmos SDK and Tendermint consensus. It powers the Crypto.com ecosystem while offering a familiar developer experience for Solidity teams.

### Production-Ready Performance

- \~5–6 second block times with immediate probabilistic finality
- Scales via IBC interoperability with the broader Cosmos network
- Optimized for low fees (fractions of a cent per transaction)

### Strong Ecosystem & Liquidity

- Native integration with Crypto.com App and Exchange
- 1M+ unique addresses and $100M+ TVL across DeFi protocols
- Bridges to Ethereum, Cosmos Hub, and other chains via Gravity Bridge & IBC

### Developer-Friendly Tooling

- Full Ethereum JSON-RPC surface, compatible with Hardhat, Foundry, Truffle
- EVM bytecode equivalence, deploy existing Solidity contracts without changes
- Rich tooling for gaming (Cronos Play), DeFi, and NFTs

## Quick Start

Connect to Cronos with Dwellir's globally distributed infrastructure:

Cronos shared endpoints currently publish mainnet access in the public catalog. If you need a separate testnet endpoint, contact our team for provisioning.

## Network Information

| Parameter          | Value         | Details |
| ------------------ | ------------- | ------- |
| Mainnet Chain ID   | 25 (0x19)     |         |
| Testnet Chain ID   | 338 (0x152)   |         |
| Native Token       | CRO           |         |
| Average Block Time | \~5.6 seconds |         |

## Installation & Setup

ethers.js v6
web3.js
viem
web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const { chainId } = await provider.getNetwork();
console.log('Cronos chain ID:', chainId); // 25n

const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);
```

```javascript
import Web3 from 'web3';

const web3 = new Web3('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const gasPrice = await web3.eth.getGasPrice();
console.log('Cronos gas price (wei):', gasPrice);

const balance = await web3.eth.getBalance('0x000000000000000000000000000000000000dead');
console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'CRO');
```

```typescript
import { createPublicClient, defineChain, http } from 'viem';

const cronos = defineChain({
  id: 25,
  name: 'Cronos',
  nativeCurrency: { name: 'Cronos', symbol: 'CRO', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'] }
  }
});

const client = createPublicClient({ chain: cronos, transport: http() });

const gas = await client.estimateGas({
  account: '0x000000000000000000000000000000000000dead',
  to: '0x0000000000000000000000000000000000000000',
  value: 0n
});
console.log('Estimated gas:', gas);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

assert w3.is_connected()
print('Chain ID:', w3.eth.chain_id)  # 25

tx_count = w3.eth.get_transaction_count('0x0000000000000000000000000000000000000000')
print('Nonce:', tx_count)
```

## API Reference

Cronos exposes the standard Ethereum JSON-RPC interface. Method deep-dives will be added soon; use the dropdown for existing guides and compatibility hints.

Cronos shared RPC endpoints do not expose Optimism-style rollup helpers such as `rollup_getInfo`, `rollup_gasPrices`, or `eth_estimateL1Fee`.

## Network Architecture

- **Consensus**: Proof-of-Authority (PoA) variant built on Tendermint for fast finality
- **IBC Enabled**: Interoperates with Cosmos Hub, Crypto.org, and other IBC networks
- **Gravity Bridge**: Facilitates asset transfers to/from Ethereum and other ERC-20 ecosystems
- **Cronos Play**: Middleware stack for game developers integrating Unity, Unreal, and C++ SDKs

## Bridging Assets

- **Cronos Bridge**: [bridge.cronos.org](https://cronos.org/bridge/) for ETH  CRO transfers
- **Gravity Bridge**: Move ERC-20 tokens from Ethereum without centralized custody
- **IBC Transfers**: Swap assets between Cronos and Cosmos chains using IBC-enabled wallets like Keplr

## Best Practices

1. **Gas Strategy:** Fetch `eth_feeHistory` or `eth_gasPrice` to adapt to variable network load.
2. **Unit Conventions:** Gas is paid in CRO (18 decimals). Use `web3.utils.toWei` or viem helpers to avoid rounding errors.
3. **Monitor Finality:** Wait for a few confirmations, usually 3 to 5 blocks, before acting on large-value transfers.
4. **Use IBC Safely:** Confirm counterparty channel IDs when transferring assets cross-chain.

## Tooling & Resources

- [Cronos Documentation](https://docs.cronos.org/)
- [Cronoscan Explorer](https://explorer.cronos.org/)
- [Testnet Explorer](https://explorer.cronos.org/testnet)
- [Get a Dwellir API Key](https://dashboard.dwellir.com/register)

Start building performant, EVM-compatible apps on Cronos with Dwellir's resilient infrastructure.

---

## debug_traceBlock - Cronos RPC Method

# debug_traceBlock - Cronos RPC Method

Traces all transactions in a block on Cronos by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Cronos - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for Cronos developers building DeFi and payment applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Cronos
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Cronos:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Cronos blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/cronos/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/cronos/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/cronos/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/cronos/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Cronos RPC Method

# debug_traceBlockByHash - Cronos RPC Method

Traces all transactions in a block on Cronos identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Cronos - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for Cronos developers building DeFi and payment applications:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Cronos
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Cronos:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Cronos:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/cronos/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/cronos/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/cronos/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/cronos/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/cronos/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Cronos RPC Method

# debug_traceBlockByNumber - Cronos RPC Method

Traces all transactions in a block on Cronos identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Cronos - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for Cronos developers building DeFi and payment applications:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Cronos execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Cronos:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Cronos:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/cronos/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/cronos/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/cronos/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/cronos/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Cronos RPC Method

# debug_traceCall - Cronos RPC Method

Traces a call on Cronos without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Cronos - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for Cronos developers building DeFi and payment applications:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Cronos
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "data": "0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
        "data": "0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
        "data": "0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    data: '0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    data: '0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    'data': '0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
        "data": "0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Cronos to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Cronos:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Cronos:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/cronos/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/cronos/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/cronos/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/cronos/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Cronos RPC Method

# debug_traceTransaction - Cronos RPC Method

Traces a transaction execution on Cronos by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Cronos
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/cronos/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/cronos/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Cronos RPC Method

# eth_accounts - Cronos RPC Method

Returns a list of addresses owned by the client on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for Cronos developers building DeFi and payment applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/cronos/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/cronos/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Cronos RPC Method

# eth_blockNumber - Cronos RPC Method

Returns the number of the most recent block on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_blockNumber` is fundamental for Cronos developers building DeFi and payment applications:

- **Syncing Applications** - Keep your dApp in sync with the latest Cronos blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Cronos block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Cronos block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Cronos block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Cronos block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Cronos block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Cronos:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Cronos:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Cronos node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/cronos/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/cronos/eth_syncing) - Check if node is still syncing

---

## eth_call - Cronos RPC Method

# eth_call - Cronos RPC Method

Executes a new message call immediately without creating a transaction on Cronos. Used for reading smart contract state.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

The `eth_call` method serves these key scenarios for Cronos developers building DeFi and payment applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Cronos
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';
const walletAddress = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Cronos. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Cronos
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Cronos

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "data": "0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "data": "0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    data := common.FromHex("0x70a082310000000000000000000000005C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Cronos RPC Method

# eth_chainId - Cronos RPC Method

Returns the chain ID used for transaction signing on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_chainId` is essential for Cronos developers building DeFi and payment applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/cronos/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/cronos/eth_syncing) - Check sync status

---

## eth_coinbase - Cronos RPC Method

# eth_coinbase - Cronos RPC Method

Checks the legacy `eth_coinbase` compatibility method on Cronos. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for Cronos developers building DeFi and payment applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Cronos coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Cronos coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Cronos coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Cronos coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Cronos coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Cronos nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/cronos/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/cronos/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/cronos/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Cronos RPC Method

# eth_estimateGas - Cronos RPC Method

Estimates the gas necessary to execute a transaction on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for Cronos developers building DeFi and payment applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Cronos
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Cronos.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Cronos may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "to": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/cronos/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Cronos Compatibility Note

# eth_estimateL1Fee - Cronos Compatibility Note

Cronos shared RPC endpoints do not expose Optimism-style L1 fee estimation. If you call `eth_estimateL1Fee` on Cronos, the endpoint responds with `-32601` because the method is not available.

## When to Use This Page

Use this page when you are checking whether an endpoint exposes rollup-specific fee helpers. On Cronos, standard fee estimation comes from `eth_estimateGas` and `eth_gasPrice`.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [{
          "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
          "to": "0x4200000000000000000000000000000000000006",
          "value": "0xde0b6b3a7640000",
          "data": "0xa9059cbb0000000000000000000000008ba1f109551bd432803012645hac136c0000000000000000000000000000000000000000000000000de0b6b3a7640000"
        }],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Fee estimation payload returned by nodes that implement eth_estimateL1Fee

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_estimateL1Fee does not exist/is not available"
  }
}
```

## Cronos Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_estimateL1Fee does not exist/is not available"
  }
}
```

## Practical Fallback

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateCronosFee(tx) {
  const [gasEstimate, gasPriceHex] = await Promise.all([
    provider.estimateGas(tx),
    provider.send('eth_gasPrice', []),
  ]);

  return {
    gasEstimate,
    gasPriceWei: BigInt(gasPriceHex),
    estimatedCostWei: gasEstimate * BigInt(gasPriceHex),
  };
}
```

## Supported Alternatives

- Use `eth_estimateGas` for execution cost.
- Use `eth_gasPrice` for current gas pricing.
- Use the Optimism documentation if you need a separate L1 data fee oracle.

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Cronos documentation](https://www.dwellir.com/docs/cronos).*

---

## eth_feeHistory - Cronos RPC Method

# eth_feeHistory - Cronos RPC Method

Returns historical gas fee data on Cronos, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for Cronos developers building DeFi and payment applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Cronos without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Cronos.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Cronos) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/cronos/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/cronos/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Cronos RPC Method

# eth_gasPrice - Cronos RPC Method

Returns the current gas price on Cronos in wei.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for Cronos developers building DeFi and payment applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Cronos
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Cronos. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Cronos, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Cronos: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Cronos supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/cronos/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/cronos/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Cronos RPC Method

# eth_getBalance - Cronos RPC Method

Returns the balance of a given address on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getBalance` is fundamental for Cronos developers building DeFi and payment applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Cronos
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Cronos
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Cronos. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Cronos`);
  return balance;
}

displayBalance('0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Cronos at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Cronos')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Cronos')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Cronos.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/cronos/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/cronos/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Cronos RPC Method

# eth_getBlockByHash - Cronos RPC Method

Returns information about a block by hash on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getBlockByHash` is essential for Cronos developers building DeFi and payment applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Cronos
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the EVM-compatible Crypto.com blockchain
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Cronos.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the EVM-compatible Crypto.com blockchain.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Cronos.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/cronos/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Cronos RPC Method

# eth_getBlockByNumber - Cronos RPC Method

Returns information about a block by block number on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getBlockByNumber` is essential for Cronos developers building DeFi and payment applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Cronos
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the EVM-compatible Crypto.com blockchain

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Cronos with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Cronos. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the EVM-compatible Crypto.com blockchain expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/cronos/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/cronos/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/cronos/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Cronos RPC Method

# eth_getBlockReceipts - Cronos RPC Method

Returns all transaction receipts for a block on Cronos. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getBlockReceipts` is useful for Cronos developers building DeFi and payment applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Cronos, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Cronos. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the EVM-compatible Crypto.com blockchain, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc8a64cd89ea7954a5f8064bf7c5fb907226e1dbb66a05d6043f7052191686f06",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/cronos/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/cronos/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Cronos RPC Method

# eth_getCode - Cronos RPC Method

Returns the bytecode at a given address on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getCode` is essential for Cronos developers building DeFi and payment applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Cronos
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Cronos:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Cronos:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/cronos/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/cronos/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Cronos RPC Method

# eth_getFilterChanges - Cronos RPC Method

Polls a filter on Cronos for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getFilterChanges` is essential for Cronos developers building DeFi and payment applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Cronos
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Cronos:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/cronos/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/cronos/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/cronos/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/cronos/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/cronos/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Cronos RPC Method

# eth_getFilterLogs - Cronos RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Cronos. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getFilterLogs` is essential for Cronos developers building DeFi and payment applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Cronos
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/cronos/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/cronos/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/cronos/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/cronos/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Cronos RPC Method

# eth_getLogs - Cronos RPC Method

Returns an array of all logs matching a given filter object on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for Cronos developers building DeFi and payment applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Cronos for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Cronos
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Cronos.

```javascript
const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Cronos Rate Limits

On Cronos, `eth_getLogs` queries are subject to a **maximum block range of 500 blocks**. This means the difference between `fromBlock` and `toBlock` cannot exceed 500 blocks per request.

Additionally, each query can return a **maximum of 10,000 log entries**.

For querying larger block ranges, split your requests into smaller batches:

```javascript
// Example: Query in 500-block batches
const BATCH_SIZE = 500;
let fromBlock = startBlock;

while (fromBlock <= endBlock) {
  const toBlock = Math.min(fromBlock + BATCH_SIZE - 1, endBlock);
  const logs = await provider.getLogs({ fromBlock, toBlock, ...filter });
  // Process logs
  fromBlock = toBlock + 1;
}
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Cronos enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Cronos, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/cronos/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/cronos/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Cronos RPC Method

# eth_getStorageAt - Cronos RPC Method

Returns the value from a storage position at a given address on Cronos. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getStorageAt` is essential for Cronos developers building DeFi and payment applications:

- **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 DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **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": [
    "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "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-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23', '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-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';

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-cronos-mainnet-archive.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 = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
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-cronos-mainnet-archive.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-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    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 Cronos:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.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-cronos-mainnet-archive.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 = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';
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 Cronos:`);
  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/cronos/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/cronos/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/cronos/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Cronos RPC Method

# eth_getTransactionByHash - Cronos RPC Method

Returns the information about a transaction by transaction hash on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getTransactionByHash` is essential for Cronos developers building DeFi and payment applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Cronos
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the EVM-compatible Crypto.com blockchain

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Cronos. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Cronos. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the EVM-compatible Crypto.com blockchain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/cronos/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Cronos RPC Method

# eth_getTransactionCount - Cronos RPC Method

Returns the number of transactions sent from an address on Cronos, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getTransactionCount` is essential for Cronos developers building DeFi and payment applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Cronos
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Cronos nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23'
nonce = get_transaction_count(address)
print(f'Cronos nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Cronos nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Cronos:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/cronos/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/cronos/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/cronos/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Cronos RPC Method

# eth_getTransactionReceipt - Cronos RPC Method

Returns the receipt of a transaction by transaction hash on Cronos. Receipt is only available for mined transactions.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_getTransactionReceipt` is essential for Cronos developers building DeFi and payment applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Cronos and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the EVM-compatible Crypto.com blockchain by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Cronos. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Cronos, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the EVM-compatible Crypto.com blockchain. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the EVM-compatible Crypto.com blockchain
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x159952dbecdbb7c17e962de632fe2560cddcdb371b4d98f37015e3682669f39c")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/cronos/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/cronos/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Cronos RPC Method

# eth_hashrate - Cronos RPC Method

Returns the legacy `eth_hashrate` compatibility value on Cronos. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for Cronos developers building DeFi and payment applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Cronos hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Cronos hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Cronos hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Cronos hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Cronos hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/cronos/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/cronos/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/cronos/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Cronos RPC Method

# eth_maxPriorityFeePerGas - Cronos RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Cronos. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for Cronos developers building DeFi and payment applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Cronos
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Cronos priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Cronos priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Cronos priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Cronos:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Cronos:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/cronos/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/cronos/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/cronos/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Cronos RPC Method

# eth_mining - Cronos RPC Method

Checks the legacy `eth_mining` compatibility method on Cronos. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for Cronos developers building DeFi and payment applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Cronos mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Cronos mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Cronos mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Cronos mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Cronos mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/cronos/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/cronos/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/cronos/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Cronos RPC Method

# eth_newBlockFilter - Cronos RPC Method

Creates a filter on Cronos that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_newBlockFilter` is essential for Cronos developers building DeFi and payment applications:

- **Block Monitoring** - Detect new blocks on Cronos as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Cronos:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/cronos/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/cronos/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/cronos/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/cronos/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Cronos RPC Method

# eth_newFilter - Cronos RPC Method

Creates a filter object on Cronos based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_newFilter` is essential for Cronos developers building DeFi and payment applications:

- **Event Monitoring** - Subscribe to specific contract events on Cronos such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Cronos:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/cronos/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/cronos/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/cronos/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/cronos/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/cronos/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Cronos RPC Method

# eth_newPendingTransactionFilter - Cronos RPC Method

Creates a filter on Cronos that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for Cronos developers building DeFi and payment applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on Cronos to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for DeFi protocols, NFT marketplaces, and Crypto.com ecosystem integrations

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Cronos...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Cronos:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/cronos/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/cronos/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/cronos/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Cronos RPC Method

# eth_protocolVersion - Cronos RPC Method

Returns the current Ethereum protocol version used by the Cronos node.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_protocolVersion` is useful for Cronos developers building DeFi and payment applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Cronos protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Cronos protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Cronos protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Cronos protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Cronos protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Cronos nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/cronos/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/cronos/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/cronos/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Cronos RPC Method

# eth_sendRawTransaction - Cronos RPC Method

Submits a pre-signed transaction for broadcast to Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for Cronos developers building DeFi and payment applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Cronos
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Cronos mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/cronos/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/cronos/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/cronos/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Cronos RPC Method

# eth_sendTransaction - Cronos RPC Method

Creates and sends a new transaction from an unlocked account on Cronos. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for Cronos developers building DeFi and payment applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Cronos tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Cronos tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Cronos tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Cronos tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Cronos tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Cronos dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/cronos/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/cronos/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Cronos RPC Method

# eth_signTransaction - Cronos RPC Method

Signs a transaction with the private key of the specified account on Cronos without submitting it to the network.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for Cronos developers building DeFi and payment applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Cronos tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Cronos tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Cronos tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Cronos:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/cronos/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/cronos/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/cronos/eth_accounts) - List accounts available for signing

---

## eth_syncing - Cronos RPC Method

# eth_syncing - Cronos RPC Method

Returns the sync status of your Cronos node - either `false` when fully synced, or an object describing the sync progress.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_syncing` is essential for Cronos developers building DeFi and payment applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Cronos node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Cronos node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Cronos node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/cronos/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/cronos/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/cronos/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/cronos/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Cronos RPC Method

# eth_uninstallFilter - Cronos RPC Method

Removes a filter on Cronos that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`eth_uninstallFilter` is important for Cronos developers building DeFi and payment applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/cronos/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/cronos/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/cronos/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/cronos/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/cronos/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Cronos RPC Method

# net_listening - Cronos RPC Method

Checks whether the connected Cronos client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`net_listening` is useful for Cronos developers building DeFi and payment applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Cronos node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Cronos node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Cronos node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/cronos/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/cronos/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/cronos/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/cronos/web3_clientVersion) - Get node client info

---

## net_peerCount - Cronos RPC Method

# net_peerCount - Cronos RPC Method

Returns the number of peers currently connected to your Cronos node.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`net_peerCount` is important for Cronos developers building DeFi and payment applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Cronos deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Cronos peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Cronos peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Cronos peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Cronos nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/cronos/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/cronos/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/cronos/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/cronos/web3_clientVersion) - Get node client info

---

## net_version - Cronos RPC Method

# net_version - Cronos RPC Method

Returns the current network ID on Cronos as a decimal string. The network ID identifies which network the node is connected to.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`net_version` is essential for Cronos developers building DeFi and payment applications:

- **Endpoint Identification** - Confirm your application is connected to the expected Cronos network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Cronos network ID:', networkId);

// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Cronos network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Cronos network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/cronos/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/cronos/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/cronos/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/cronos/eth_syncing) - Check node sync progress

---

## rollup_gasPrices - Cronos Compatibility Note

# rollup_gasPrices - Cronos Compatibility Note

Cronos shared RPC endpoints do not expose Optimism-style rollup gas pricing. If you call `rollup_gasPrices` on Cronos, the endpoint responds with `-32601` because the method is not available.

## When to Use This Page

Use this page when you are checking whether an endpoint exposes rollup-specific pricing. For Cronos, use standard Ethereum JSON-RPC pricing methods instead.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup gas pricing returned by Optimism-style rollup endpoints. Cronos shared RPC endpoints do not expose this method.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "l1GasPrice": "0x34630b8a00",
    "l2GasPrice": "0x1dcd6500"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method rollup_gasPrices does not exist/is not available"
  }
}
```

## What to Use on Cronos Instead

- `eth_gasPrice` for the current gas price.
- `eth_estimateGas` for transaction execution cost.
- `eth_feeHistory` if you need historical gas trend data and the client supports it.

## Fallback Example

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getCronosFeeData() {
  const [gasPriceHex, feeData] = await Promise.all([
    provider.send('eth_gasPrice', []),
    provider.getFeeData(),
  ]);

  return {
    gasPriceWei: BigInt(gasPriceHex),
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  };
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Cronos documentation](https://www.dwellir.com/docs/cronos).*

---

## rollup_getInfo - Cronos Compatibility Note

# rollup_getInfo - Cronos Compatibility Note

Cronos shared RPC endpoints do not expose Optimism-style rollup metadata. On the live Cronos archive endpoint, `rollup_getInfo` returns `-32601` because the method is not available.

## When to Use This Page

Use this page when you need to confirm whether an endpoint is actually Optimism-compatible. On Cronos, prefer standard Ethereum JSON-RPC methods such as `eth_chainId`, `net_version`, `eth_gasPrice`, and `eth_estimateGas`.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_getInfo",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup metadata object returned by nodes that implement rollup_getInfo

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method rollup_getInfo does not exist/is not available"
  }
}
```

## Cronos Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method rollup_getInfo does not exist/is not available"
  }
}
```

## Fallback Check

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function supportsRollupInfo() {
  try {
    await provider.send('rollup_getInfo', []);
    return true;
  } catch (error) {
    if (error?.code === -32601) {
      return false;
    }
    throw error;
  }
}

console.log('Rollup metadata available:', await supportsRollupInfo());
```

## Supported Alternatives

- Use `eth_chainId` to confirm you are connected to Cronos mainnet (`25` / `0x19`).
- Use `eth_gasPrice` and `eth_estimateGas` for normal transaction pricing on Cronos.
- Use the Optimism documentation if you need `mode`, `synced_l1`, `safe_l2`, or `unsafe_l2` fields.

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Cronos documentation](https://www.dwellir.com/docs/cronos).*

---

## rpc_modules - Cronos RPC Method

# rpc_modules - Cronos RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Cronos endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`rpc_modules` is useful for Cronos developers building DeFi and payment applications:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/cronos/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/cronos/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Cronos RPC Method

# web3_clientVersion - Cronos RPC Method

Returns the current client software version string for your Cronos node, including the client name, version number, OS, and runtime.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

## When to Use This Method

`web3_clientVersion` is valuable for Cronos developers building DeFi and payment applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Cronos client:', clientVersion);

// Using fetch
const response = await fetch('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Cronos client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Cronos client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/cronos/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/cronos/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/cronos/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/cronos/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Cronos RPC Method

# web3_sha3 - Cronos RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Cronos.

> **Why Cronos?** Build on the EVM-compatible Crypto.com blockchain with fast finality and deep Crypto.com ecosystem integration.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for Cronos developers building DeFi and payment applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-cronos-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/cronos/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/cronos/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/cronos/web3_clientVersion) - Get node client version

---

## Enjin RPC with Dwellir

# Enjin RPC with Dwellir

## Enjin RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Enjin supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Enjin Matrix?

### NFT-First Runtime

- Protocol-level NFT minting, on-chain metadata, and marketplace enforcement remove the need for bespoke smart contracts ([Enjin Blockchain overview](https://enjin.io/technology/blockchain)).
- ENJ-denominated fees are tuned for games and app developers, giving predictable operating costs for live services ([Enjin Blockchain overview](https://enjin.io/technology/blockchain)).

### Fuel Tanks & Managed Wallets

- Fuel tanks sponsor transaction fees for specific players or apps, smoothing onboarding into Matrixchain ([Fuel Tanks docs](https://docs.enjin.io/docs/creating-a-fuel-tank)).
- Managed wallets let users receive NFTs before creating self-custodial accounts, ideal for mainstream launches ([Managed wallets docs](https://docs.enjin.io/docs/using-managed-wallets)).

### Dual-Layer Security

- Matrixchain execution is secured by the Enjin Relaychain, combining Aura authoring with relay-governed GRANDPA finality ([Enjin Blockchain overview](https://enjin.io/technology/blockchain)).
- Custom matrixchains can connect while inheriting the same security and cross-chain routing primitives provided by the Relaychain ([Enjin Blockchain overview](https://enjin.io/technology/blockchain)).

## Quick Start with Enjin

Sign up at the Dwellir dashboard to generate an API key, then replace `YOUR_API_KEY` in the endpoints above. Keys can be scoped per environment to manage limits and analytics.

### Installation & Setup

cURL
Polkadot.js
Rust (subxt)
Python (py-substrate-interface)

```bash
# Health check
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"system_health","params":[],"id":1}'

# Latest finalized head
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"chain_getFinalizedHead","params":[],"id":2}'

# Runtime versions
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"state_getRuntimeVersion","params":[],"id":3}'
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const [chain, runtime, head] = await Promise.all([
  api.rpc.system.chain(),
  api.rpc.state.getRuntimeVersion(),
  api.rpc.chain.getHeader()
]);

console.log(`Connected to ${chain} specVersion ${runtime.specVersion}`);
console.log(`Best block #${head.number.toNumber()} (${head.hash.toHex()})`);

const validator = 'efS1ZdvCHHviX7qnTGZEZQX9Uz3qpibG9L5RpF9niM8ne5RBn';
const account = await api.query.system.account(validator);
console.log('Validator free balance:', account.data.free.toHuman());
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use subxt::ext::sp_core::crypto::AccountId32;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let runtime = api.rpc().runtime_version(None).await?;
    println!("specVersion={} txVersion={}", runtime.spec_version, runtime.transaction_version);

    let account: AccountId32 = "efS1ZdvCHHviX7qnTGZEZQX9Uz3qpibG9L5RpF9niM8ne5RBn".parse()?;
    let balance = api
        .storage()
        .at_latest()
        .await?
        .fetch(&subxt::dynamic::storage("System", "Account", vec![account.clone().into()]))
        .await?;
    println!("Account info: {:?}", balance);
    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(
    url="wss://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY"
)

chain = substrate.rpc_request("system_chain", [])
print("Chain:", chain["result"])

account_info = substrate.query(
    module='System',
    storage_function='Account',
    params=['efS1ZdvCHHviX7qnTGZEZQX9Uz3qpibG9L5RpF9niM8ne5RBn']
)
print("Free balance:", account_info.value['data']['free'])
```

## Network Information

| Parameter    | Value                                                              | Details                                            |
| ------------ | ------------------------------------------------------------------ | -------------------------------------------------- |
| Genesis Hash | 0x3af4ff48ec76d2efc8476730f423ac07e25ad48f5f4c9dc39c778b164d808615 | Verified via `chain_getBlockHash(0)`               |
| Runtime Spec | 1022                                                               | Transaction version 11 (`state_getRuntimeVersion`) |
| SS58 Prefix  | 1110                                                               | `system_properties` result                         |
| Native Token | ENJ                                                                | 18 decimals (`system_properties`)                  |

### Matrix Ecosystem Snapshot (3 Oct 2025)

| Parameter      | Value                                         | Details                                                                                                                                                                                 |
| -------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Relay Chain    | Enjin Relaychain                              | `0xd8761d3c88f26dc12875c00d3165f7d67243d56fc85b4cf19937601a7916e5a9`, verified via `chain_getBlockHash(0)` against the Enjin Relay archive RPC host `archive.relay.blockchain.enjin.io` |
| Finality       | Aura authorship with GRANDPA finality         | Shared by the Enjin Relaychain                                                                                                                                                          |
| Address Format | SS58 prefix `1110`                            | Returned by `system_properties` against the Enjin Matrix archive RPC host `archive.matrix.blockchain.enjin.io`                                                                          |
| Runtime        | Spec version `1022`, transaction version `11` | `state_getRuntimeVersion` against the Enjin Matrix archive RPC host `archive.matrix.blockchain.enjin.io`                                                                                |
| Explorers      | [Matrix Console](https://console.enjin.io)    | Mainnet and canary                                                                                                                                                                      |
| Canary Runtime | Enjin Matrix Canary                           | `wss://api-enjin-canary-matrix.n.dwellir.com/YOUR_API_KEY`                                                                                                                              |

## API Reference

Enjin Matrix exposes the standard Substrate RPC surface for node health, storage, extrinsics, and fee estimation, with additional Matrix-specific namespaces such as `fuelTanks_*`, `multitokens_*`, `ismp_*`, and `transactionWatch_v1_*` available depending on your environment and authorization scope.

> **Tip:** Use [`rpc_methods`](https://www.dwellir.com/docs/enjin/rpc_methods) to verify which optional namespaces (fuel tanks, multitokens, ISMP) are enabled for your API key and environment.

Additional Substrate namespaces such as `childstate_*`, `offchain_*`, and read-proof helpers follow the standard Substrate semantics; their availability depends on node configuration and authorization. Use `rpc_methods` to inspect support before invoking them from clients.

## Common Integration Patterns

- **Fuel tank sponsorship** – poll `fuelTanks_selectFuelTank` to determine which tank will cover fees for a user, then handle top-ups via governance-controlled accounts.
- **Managed wallet onboarding** – detect custodial wallets via metadata and migrate them to self-custody by monitoring `Balances.Transfer` events to managed accounts.
- **NFT marketplace indexing** – subscribe to `chain_subscribeFinalizedHeads`, pull block extrinsics, and decode marketplace pallets to track listings, royalty enforcement, and burns.

## Performance Best Practices

- Prefer WebSocket endpoints for subscriptions and batched queries; fall back to HTTPS for stateless reads.
- Cache runtime metadata keyed by `specVersion` to avoid re-fetching large SCALE blobs on each connection.
- Use `state_getKeysPaged` with modest page sizes (≤500) when walking storage maps to respect rate limits.
- Implement exponential backoff and retry logic for transient `429` or networking errors.

## Troubleshooting

- **Connection refused** – ensure `YOUR_API_KEY` is present and the hostname matches the region you activated in Dwellir.
- **Invalid SS58** – use prefix `1110` when encoding Matrixchain addresses; relay chain accounts use prefix `2135`.
- **Extrinsic failures** – decode the `DispatchError` using the latest metadata; many marketplace pallets return module-specific error codes.
- **Missing custom RPCs** – extend Polkadot.js type bundles with Enjin-specific RPC definitions when `API/INIT` warns about undecorated methods.

## Smoke Tests

Run these endpoints after deployment to validate connectivity:

```bash
# Health (should report peers > 0)
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"system_health","params":[],"id":1}'

# Latest finalized hash
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"chain_getFinalizedHead","params":[],"id":2}'

# Runtime versions
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"state_getRuntimeVersion","params":[],"id":3}'

# RPC surface area
curl -s https://api-enjin-matrixchain.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"rpc_methods","params":[],"id":4}'
```

## Migration Guide (Polkadot/Westend → Enjin Matrix)

1. **Endpoints** – replace legacy Polkadot/Westend RPC URLs with Dwellir Matrix endpoints listed above.
2. **Address format** – re-encode accounts with SS58 prefix `1110`; update wallet tooling accordingly.
3. **Fee economics** – call `payment_queryInfo` to account for ENJ-denominated fees and optional fuel tank sponsorships.
4. **Runtime pallets** – verify availability of Matrix-specific pallets (fuel tanks, managed wallets) and adjust type bundles.
5. **Event handling** – update indexers to interpret Enjin marketplace and multitoken events instead of Polkadot parachain events.

## Resources & Tools

- [Enjin Blockchain Technology Overview](https://enjin.io/technology/blockchain) – architecture, performance targets, and ecosystem highlights.
- [Console Explorer](https://console.enjin.io) – monitor blocks, accounts, and collections across mainnet and canary.
- [Dwellir Dashboard](https://dashboard.dwellir.com) – manage API keys, usage analytics, and plan limits.
- [Subscan (Matrixchain)](https://matrix.subscan.io) – alternative explorer for validators and extrinsics.

***

Ready to go live? Deploy against Matrix mainnet using Dwellir’s globally anycasted infrastructure, then automate observability with the smoke tests above.

---

## author_pendingExtrinsics - Enjin RPC Method

# author_pendingExtrinsics - Enjin RPC Method

Returns all pending extrinsics currently in the transaction pool on Enjin. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`author_pendingExtrinsics` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Enjin
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Enjin transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/enjin/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/enjin/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/enjin/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Enjin RPC Method

# author_rotateKeys - Enjin RPC Method

Generate a new set of session keys on Enjin. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`author_rotateKeys` is critical for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Validator Setup** - Generate initial session keys when setting up a new validator on high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Enjin:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/enjin/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/enjin/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Enjin RPC Method

# author_submitAndWatchExtrinsic - Enjin RPC Method

Submits a signed extrinsic to Enjin and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Enjin
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://enjin-matrix-rpc.n.dwellir.com

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://enjin-matrix-rpc.n.dwellir.com');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://enjin-matrix-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://enjin-matrix-rpc.n.dwellir.com").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/enjin/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/enjin/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/enjin/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/enjin/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Enjin RPC Method

# author_submitExtrinsic - Enjin RPC Method

Submits a fully signed extrinsic to Enjin for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`author_submitExtrinsic` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Token Transfers** -- Send native tokens or assets between accounts on Enjin
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://enjin-matrix-rpc.n.dwellir.com").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/enjin/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/enjin/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Enjin RPC Method

# beefy_getFinalizedHead - Enjin RPC Method

Returns the block hash of the latest BEEFY-finalized block on Enjin. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`beefy_getFinalizedHead` is important for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://enjin-matrix-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://enjin-matrix-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/enjin/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/enjin/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Enjin RPC Method

# chain_getBlock - Enjin RPC Method

Retrieves complete block information from Enjin, including the block header, extrinsics, and justifications.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://enjin-matrix-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://enjin-matrix-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://enjin-matrix-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/enjin/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/enjin/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/enjin/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Enjin RPC Method

# chain_getBlockHash - Enjin RPC Method

Returns the block hash for a given block number on Enjin. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`chain_getBlockHash` is fundamental for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Enjin
- **Block Navigation** - Navigate the blockchain history for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Enjin
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://enjin-matrix-rpc.n.dwellir.com'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Enjin for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Enjin state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Enjin network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/enjin/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/enjin/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Enjin RPC Method

# chain_getFinalizedHead - Enjin RPC Method

Returns the hash of the last finalized block on Enjin. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`chain_getFinalizedHead` is critical for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Enjin
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://enjin-matrix-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://enjin-matrix-rpc.n.dwellir.com', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Enjin:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/enjin/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/enjin/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Enjin RPC Method

# chain_getHeader - Enjin RPC Method

Returns the block header for a given hash on Enjin. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`chain_getHeader` is ideal for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Enjin
- **Chain Synchronization** - Track block production and monitor chain progress for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://enjin-matrix-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Enjin:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Enjin chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Enjin block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/enjin/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Enjin RPC Method

# chain_subscribeFinalizedHeads - Enjin RPC Method

Subscribe to receive notifications when blocks are finalized on Enjin. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Exchange Deposits** - Only credit funds after finalization for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://enjin-matrix-rpc.n.dwellir.com`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://enjin-matrix-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://enjin-matrix-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Enjin:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/enjin/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/enjin/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Enjin RPC Method

# chain_subscribeNewHeads - Enjin RPC Method

Subscribe to receive notifications when new block headers are produced on Enjin. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`chain_subscribeNewHeads` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Block Monitoring** - Track new blocks in real time on Enjin for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://enjin-matrix-rpc.n.dwellir.com`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://enjin-matrix-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://enjin-matrix-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Enjin as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Enjin:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/enjin/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/enjin/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Enjin RPC Method

# grandpa_roundState - Enjin RPC Method

Returns the state of the current GRANDPA finality round on Enjin when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`grandpa_roundState` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Enjin, critical for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/enjin/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/enjin/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/enjin/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Enjin RPC Method

# payment_queryFeeDetails - Enjin RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Enjin. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`payment_queryFeeDetails` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Enjin
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/enjin/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/enjin/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/enjin/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/enjin/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Enjin RPC Method

# payment_queryInfo - Enjin RPC Method

Estimates the fee for an encoded extrinsic on Enjin. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`payment_queryInfo` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Enjin
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/enjin/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/enjin/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/enjin/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/enjin/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Enjin RPC Method

# rpc_methods - Enjin RPC Method

Returns a list of all RPC methods exposed by the Enjin node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`rpc_methods` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Enjin node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Enjin endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://enjin-matrix-rpc.n.dwellir.com', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Enjin endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/enjin/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/enjin/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Enjin RPC Method

# state_call - Enjin RPC Method

Calls a runtime API function on Enjin and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`state_call` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/enjin/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/enjin/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/enjin/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns a list of storage keys that share a given prefix. This method is helpful when you need to discover child keys beneath a map, such as iterating through all system accounts or fuel tank records in Enjin Matrix.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage prefix (typically `twox128(module) + hasher(storage)`)
- `blockHash` (`string | null, optional`): Block hash for historical queries; `null` uses the best block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7",
    null
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): An array of hex-encoded storage keys matching the supplied prefix.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac",
    "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850",
    "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96",
    "…"
  ],
  "id": 1
}
```

## Response Example (truncated)

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac",
    "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850",
    "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96",
    "…"
  ],
  "id": 1
}
```

## Tips

- Use `state_getKeysPaged` for large datasets; it adds pagination controls to avoid heavy responses.
- Combine with `state_getStorage` to fetch the associated values for each discovered key.
- Remember that map storage keys append hashes and encoded keys (e.g., `Blake2_128Concat(AccountId)`), so you may need to post-process the suffix.

---

## state_getKeysPaged - Enjin RPC Method

# state_getKeysPaged - Enjin RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Enjin. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`state_getKeysPaged` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Enjin
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://enjin-matrix-rpc.n.dwellir.com";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/enjin/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/enjin/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Enjin RPC Method

# state_getMetadata - Enjin RPC Method

Returns the runtime metadata for Enjin as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`state_getMetadata` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Enjin
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://enjin-matrix-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Enjin:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Enjin:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/enjin/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/enjin/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Enjin RPC Method

# state_getRuntimeVersion - Enjin RPC Method

Returns the runtime version information for Enjin, including the spec name, spec version, implementation version, and supported API versions.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`state_getRuntimeVersion` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Enjin
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://enjin-matrix-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Enjin in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/enjin/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Enjin RPC Method

# state_getStorage - Enjin RPC Method

Returns the SCALE-encoded storage value for a given key on Enjin. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`state_getStorage` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Enjin
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/enjin/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/enjin/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Enjin RPC Method

# state_queryStorageAt - Enjin RPC Method

Queries multiple storage keys at a specific block on Enjin, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`state_queryStorageAt` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Enjin
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/enjin/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/enjin/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/enjin/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/enjin/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Enjin RPC Method

# system_chain - Enjin RPC Method

Returns the chain name of the Enjin network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`system_chain` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Network Verification** -- Confirm your application is connected to the correct Enjin network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Enjin"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://enjin-matrix-rpc.n.dwellir.com', 'Enjin');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/enjin/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/enjin/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/enjin/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/enjin/rpc_methods) -- List all available RPC methods

---

## system_health - Enjin RPC Method

# system_health - Enjin RPC Method

Returns the health status of the Enjin node, including peer count, sync state, and whether the node expects to have peers.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`system_health` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Enjin
- **Load Balancing** - Route requests only to healthy, fully synced nodes for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://enjin-matrix-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://enjin-matrix-rpc.n.dwellir.com"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Enjin:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Enjin nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://enjin-matrix-rpc.n.dwellir.com')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/enjin/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Enjin RPC Method

# system_name - Enjin RPC Method

Returns the node implementation name on Enjin. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`system_name` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Enjin
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Enjin node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Enjin node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Enjin node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
name = substrate.rpc_request('system_name', [])['result']
print(f'Enjin node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Enjin node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Enjin nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/enjin/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/enjin/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/enjin/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/enjin/rpc_methods) -- List all available RPC methods

---

## system_properties - Enjin RPC Method

# system_properties - Enjin RPC Method

Returns the chain-specific properties for Enjin, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`system_properties` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Enjin
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/enjin/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/enjin/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/enjin/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/enjin/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/enjin/rpc_methods) -- List all available RPC methods

---

## system_version - Enjin RPC Method

# system_version - Enjin RPC Method

Returns the node implementation version string on Enjin. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Enjin?** Build on the purpose-built NFT blockchain with protocol-level minting and $100M Metaverse Fund with NFT functions at protocol level, Fuel Tanks for subsidized fees, 700-1000 TPS, 6-second finality, and ERC-1155 standard pioneer.

## When to Use This Method

`system_version` is essential for game developers, NFT creators, and enterprises building cross-chain digital assets:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Enjin
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for high-volume NFT minting (2,000+ per tx), gaming assets, and cross-chain NFT transfers via Paratoken standard
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://enjin-matrix-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://enjin-matrix-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Enjin node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://enjin-matrix-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Enjin node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://enjin-matrix-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Enjin node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://enjin-matrix-rpc.n.dwellir.com')
version = substrate.rpc_request('system_version', [])['result']
print(f'Enjin node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://enjin-matrix-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Enjin node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Enjin nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/enjin/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/enjin/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/enjin/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/enjin/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/enjin/rpc_methods) -- List all available RPC methods

---

## Ethereum RPC with Dwellir

# Ethereum RPC with Dwellir

## Ethereum RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Ethereum supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Ethereum?

Ethereum is the original and most established smart contract platform, offering unparalleled security, decentralization, and ecosystem support:

### **Unmatched Security**

- **Longest-running proof-of-stake network** - Battle-tested since 2015, secured by PoS since 2022
- **$100B+ in value secured** - Highest total value locked across all chains
- **10,000+ validators** - Maximally decentralized consensus mechanism

### **Largest Ecosystem**

- **3,000+ dApps** - Richest application ecosystem in web3
- **$50B+ DeFi TVL** - Largest decentralized finance ecosystem
- **Major institutions** - Direct integration by Fortune 500 companies

### **Developer Excellence**

- **EVM standard** - Reference implementation for smart contract execution
- **Mature tooling** - Best-in-class development frameworks and libraries
- **Network effects** - Largest community of developers and users

## Quick Start with Ethereum

Connect to Ethereum in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Ethereum mainnet
const provider = new JsonRpcProvider(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Ethereum mainnet
const web3 = new Web3(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Ethereum:', chainId === 1);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';

// Create Ethereum client
const client = createPublicClient({
  chain: mainnet,
  transport: http('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to Ethereum mainnet
web3 = Web3(Web3.HTTPProvider(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection
print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)

# Get latest block
latest_block = web3.eth.get_block('latest')
print(f'Latest block: {latest_block.number}')
```

## Network Information

| Parameter    | Value      | Details      |
| ------------ | ---------- | ------------ |
| Chain ID     | 1          | Mainnet      |
| Block Time   | 12 seconds | Average      |
| Gas Token    | ETH        | Native token |
| RPC Standard | Ethereum   | JSON-RPC 2.0 |

## API Reference

Ethereum supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/).

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Check transaction status
  if (receipt.status === 1) {
    console.log('Transaction successful');
  } else {
    console.log('Transaction failed');
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Ethereum mainnet:

```javascript
// Get current fee data (EIP-1559)
const feeData = await provider.getFeeData();

// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Calculate total cost
const totalCost = gasEstimate * feeData.gasPrice;
console.log('Estimated cost:', totalCost);
```

### Event Filtering

Efficiently query contract events with proper pagination:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Recommended batch size
  const latestBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= latestBlock; i += batchSize) {
    const toBlock = Math.min(i + batchSize - 1, latestBlock);
    const batch = await contract.queryFilter(filter, i, toBlock);
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class EthereumProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for gas"

Ethereum transactions require ETH for gas fees:

```javascript
// Always account for gas in balance checks
const balance = await provider.getBalance(address);
const gasPrice = await provider.getGasPrice();
const gasLimit = await provider.estimateGas(tx);
const gasCost = gasPrice * gasLimit;

if (balance < (tx.value + gasCost)) {
  throw new Error(`Need ${(tx.value + gasCost) - balance} more wei`);
}
```

### Error: "Transaction underpriced"

Use current market gas prices:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Smoke Tests

### Test Connection with cURL

```bash
# Test Ethereum mainnet
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Test Ethereum Sepolia
curl -X POST https://api-ethereum-sepolia.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Test with Ethers.js

```javascript
// Test mainnet connection
const mainnetProvider = new JsonRpcProvider(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const blockNumber = await mainnetProvider.getBlockNumber();
const network = await mainnetProvider.getNetwork();

console.log('Block number:', blockNumber);
console.log('Chain ID:', network.chainId); // Should be 1n
```

### Test with Web3.py

```python
from web3 import Web3

# Test connection
web3 = Web3(Web3.HTTPProvider(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
))

print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # Should be 1
print('Block number:', web3.eth.block_number)
```

## Migration Guide

### Migrating to Dwellir

Replace your existing RPC endpoint with Dwellir:

```javascript
// Before
const provider = new JsonRpcProvider('https://other-provider.com');

// After
const provider = new JsonRpcProvider(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// All existing code works identically
// Same JSON-RPC methods supported
// Same response formats
// Note: Update your API endpoint URL
// Note: Add your Dwellir API key
```

## Resources & Tools

### Official Resources

- [Ethereum Documentation](https://ethereum.org/en/developers/)
- [EIP Standards](https://eips.ethereum.org/)
- [Etherscan Block Explorer](https://etherscan.io)

### Developer Tools

- [Hardhat](https://hardhat.org/)
- [Foundry](https://getfoundry.sh/)
- [Truffle](https://trufflesuite.com/)
- [Remix IDE](https://remix.ethereum.org/)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Ethereum with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Ethereum RPC Method

# debug_traceBlock - Ethereum RPC Method

Traces all transactions in a block on Ethereum by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ethereum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Ethereum
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Ethereum:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Ethereum blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ethereum/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ethereum/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Ethereum RPC Method

# debug_traceBlockByHash - Ethereum RPC Method

Traces all transactions in a block on Ethereum identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ethereum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Ethereum
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Ethereum:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Ethereum:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/ethereum/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ethereum/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ethereum/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ethereum/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Ethereum RPC Method

# debug_traceBlockByNumber - Ethereum RPC Method

Traces all transactions in a block on Ethereum identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ethereum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Ethereum execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Ethereum:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Ethereum:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/ethereum/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ethereum/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ethereum/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Ethereum RPC Method

# debug_traceCall - Ethereum RPC Method

Traces a call on Ethereum without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Ethereum - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Ethereum
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Ethereum to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Ethereum:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Ethereum:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/ethereum/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ethereum/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Ethereum RPC Method

# debug_traceTransaction - Ethereum RPC Method

Traces a transaction execution on Ethereum by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Ethereum
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/ethereum/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ethereum/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Ethereum RPC Method

# eth_accounts - Ethereum RPC Method

Returns a list of addresses owned by the client on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, NFT creators, and enterprise blockchain teams in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/ethereum/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/ethereum/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Ethereum RPC Method

# eth_blockNumber - Ethereum RPC Method

Returns the number of the most recent block on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Syncing Applications** - Keep your dApp in sync with the latest Ethereum blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Ethereum block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Ethereum block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Ethereum block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Ethereum block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ethereum block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Ethereum:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Ethereum:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Ethereum node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ethereum/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/ethereum/eth_syncing) - Check if node is still syncing

---

## eth_call - Ethereum RPC Method

# eth_call - Ethereum RPC Method

Executes a new message call immediately without creating a transaction on Ethereum. Used for reading smart contract state.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Ethereum
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const walletAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Ethereum. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Ethereum
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Ethereum

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    data := common.FromHex("0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Ethereum RPC Method

# eth_chainId - Ethereum RPC Method

Returns the chain ID used for transaction signing on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/ethereum/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/ethereum/eth_syncing) - Check sync status

---

## eth_coinbase - Ethereum RPC Method

# eth_coinbase - Ethereum RPC Method

Checks the legacy `eth_coinbase` compatibility method on Ethereum. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, NFT creators, and enterprise blockchain teams when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Ethereum coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Ethereum coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Ethereum coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ethereum coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Ethereum coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Ethereum nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/ethereum/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/ethereum/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/ethereum/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Ethereum RPC Method

# eth_estimateGas - Ethereum RPC Method

Estimates the gas necessary to execute a transaction on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Ethereum
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Ethereum.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Ethereum may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ethereum/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Ethereum RPC Method

# eth_feeHistory - Ethereum RPC Method

Returns historical gas fee data on Ethereum, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Ethereum without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Ethereum.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Ethereum) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ethereum/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/ethereum/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Ethereum RPC Method

# eth_gasPrice - Ethereum RPC Method

Returns the current gas price on Ethereum in wei.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Ethereum
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Ethereum. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Ethereum, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Ethereum: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Ethereum supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/ethereum/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/ethereum/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Ethereum RPC Method

# eth_getBalance - Ethereum RPC Method

Returns the balance of a given address on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Ethereum
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Ethereum
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Ethereum. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Ethereum`);
  return balance;
}

displayBalance('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Ethereum at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Ethereum')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Ethereum')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Ethereum.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/ethereum/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/ethereum/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Ethereum RPC Method

# eth_getBlockByHash - Ethereum RPC Method

Returns information about a block by hash on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Ethereum
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the world's leading smart contract platform with the largest developer ecosystem
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Ethereum.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the world's leading smart contract platform with the largest developer ecosystem.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Ethereum.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/ethereum/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Ethereum RPC Method

# eth_getBlockByNumber - Ethereum RPC Method

Returns information about a block by block number on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Ethereum
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the world's leading smart contract platform with the largest developer ecosystem

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Ethereum with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Ethereum. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the world's leading smart contract platform with the largest developer ecosystem expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/ethereum/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ethereum/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ethereum/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Ethereum RPC Method

# eth_getBlockReceipts - Ethereum RPC Method

Returns all transaction receipts for a block on Ethereum. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Ethereum, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Ethereum. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the world's leading smart contract platform with the largest developer ecosystem, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ethereum/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ethereum/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Ethereum RPC Method

# eth_getCode - Ethereum RPC Method

Returns the bytecode at a given address on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Ethereum
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Ethereum:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Ethereum:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/ethereum/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/ethereum/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Ethereum RPC Method

# eth_getFilterChanges - Ethereum RPC Method

Polls a filter on Ethereum for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Ethereum
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Ethereum:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ethereum/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ethereum/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ethereum/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ethereum/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/ethereum/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Ethereum RPC Method

# eth_getFilterLogs - Ethereum RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Ethereum. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Ethereum
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ethereum/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ethereum/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/ethereum/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ethereum/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Ethereum RPC Method

# eth_getLogs - Ethereum RPC Method

Returns an array of all logs matching a given filter object on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Ethereum for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Ethereum
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Ethereum.

```javascript
const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Ethereum enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Ethereum, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ethereum/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ethereum/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Ethereum RPC Method

# eth_getStorageAt - Ethereum RPC Method

Returns the value from a storage position at a given address on Ethereum. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **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 DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **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": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "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-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '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-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

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-ethereum-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 = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
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-ethereum-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-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    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 Ethereum:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-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-ethereum-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 = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
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 Ethereum:`);
  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/ethereum/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/ethereum/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/ethereum/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Ethereum RPC Method

# eth_getTransactionByHash - Ethereum RPC Method

Returns the information about a transaction by transaction hash on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Ethereum
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the world's leading smart contract platform with the largest developer ecosystem

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Ethereum. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Ethereum. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the world's leading smart contract platform with the largest developer ecosystem.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ethereum/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Ethereum RPC Method

# eth_getTransactionCount - Ethereum RPC Method

Returns the number of transactions sent from an address on Ethereum, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Ethereum
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Ethereum nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
nonce = get_transaction_count(address)
print(f'Ethereum nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Ethereum nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Ethereum:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/ethereum/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ethereum/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ethereum/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Ethereum RPC Method

# eth_getTransactionReceipt - Ethereum RPC Method

Returns the receipt of a transaction by transaction hash on Ethereum. Receipt is only available for mined transactions.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Ethereum and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the world's leading smart contract platform with the largest developer ecosystem by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Ethereum. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Ethereum, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the world's leading smart contract platform with the largest developer ecosystem. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the world's leading smart contract platform with the largest developer ecosystem
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ethereum/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/ethereum/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Ethereum RPC Method

# eth_hashrate - Ethereum RPC Method

Returns the legacy `eth_hashrate` compatibility value on Ethereum. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Ethereum hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Ethereum hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Ethereum hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ethereum hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Ethereum hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/ethereum/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/ethereum/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/ethereum/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Ethereum RPC Method

# eth_maxPriorityFeePerGas - Ethereum RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Ethereum. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Ethereum
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Ethereum priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Ethereum priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Ethereum priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Ethereum:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Ethereum:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ethereum/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/ethereum/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ethereum/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Ethereum RPC Method

# eth_mining - Ethereum RPC Method

Checks the legacy `eth_mining` compatibility method on Ethereum. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Ethereum mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Ethereum mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Ethereum mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ethereum mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Ethereum mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/ethereum/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/ethereum/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/ethereum/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Ethereum RPC Method

# eth_newBlockFilter - Ethereum RPC Method

Creates a filter on Ethereum that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Block Monitoring** - Detect new blocks on Ethereum as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Ethereum:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ethereum/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ethereum/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/ethereum/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ethereum/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Ethereum RPC Method

# eth_newFilter - Ethereum RPC Method

Creates a filter object on Ethereum based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Event Monitoring** - Subscribe to specific contract events on Ethereum such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Ethereum:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ethereum/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ethereum/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/ethereum/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ethereum/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ethereum/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Ethereum RPC Method

# eth_newPendingTransactionFilter - Ethereum RPC Method

Creates a filter on Ethereum that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Mempool Monitoring** - Observe unconfirmed transactions on Ethereum to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Ethereum...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Ethereum:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ethereum/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ethereum/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ethereum/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Ethereum RPC Method

# eth_protocolVersion - Ethereum RPC Method

Returns the current Ethereum protocol version used by the Ethereum node.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Ethereum protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Ethereum protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Ethereum protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Ethereum protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ethereum protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Ethereum nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/ethereum/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/ethereum/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/ethereum/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Ethereum RPC Method

# eth_sendRawTransaction - Ethereum RPC Method

Submits a pre-signed transaction for broadcast to Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Ethereum
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Ethereum mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/ethereum/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/ethereum/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ethereum/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Ethereum RPC Method

# eth_sendTransaction - Ethereum RPC Method

Creates and sends a new transaction from an unlocked account on Ethereum. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, NFT creators, and enterprise blockchain teams in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Ethereum tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Ethereum tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Ethereum tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Ethereum tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ethereum tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Ethereum dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/ethereum/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/ethereum/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Ethereum RPC Method

# eth_signTransaction - Ethereum RPC Method

Signs a transaction with the private key of the specified account on Ethereum without submitting it to the network.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, NFT creators, and enterprise blockchain teams in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Ethereum tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Ethereum tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Ethereum tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Ethereum:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/ethereum/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/ethereum/eth_accounts) - List accounts available for signing

---

## eth_syncing - Ethereum RPC Method

# eth_syncing - Ethereum RPC Method

Returns the sync status of your Ethereum node - either `false` when fully synced, or an object describing the sync progress.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Ethereum node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Ethereum node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Ethereum node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/ethereum/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/ethereum/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/ethereum/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/ethereum/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Ethereum RPC Method

# eth_uninstallFilter - Ethereum RPC Method

Removes a filter on Ethereum that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ethereum/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ethereum/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/ethereum/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ethereum/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ethereum/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Ethereum RPC Method

# net_listening - Ethereum RPC Method

Checks whether the connected Ethereum client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`net_listening` is useful for DeFi developers, NFT creators, and enterprise blockchain teams:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Ethereum node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Ethereum node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Ethereum node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/ethereum/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/ethereum/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ethereum/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/ethereum/web3_clientVersion) - Get node client info

---

## net_peerCount - Ethereum RPC Method

# net_peerCount - Ethereum RPC Method

Returns the number of peers currently connected to your Ethereum node.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`net_peerCount` is important for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Ethereum deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Ethereum peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Ethereum peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Ethereum peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Ethereum nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/ethereum/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/ethereum/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ethereum/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/ethereum/web3_clientVersion) - Get node client info

---

## net_version - Ethereum RPC Method

# net_version - Ethereum RPC Method

Returns the current network ID on Ethereum as a decimal string. The network ID identifies which network the node is connected to.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`net_version` is essential for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Endpoint Identification** - Confirm your application is connected to the expected Ethereum network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Ethereum network ID:', networkId);

// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Ethereum network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ethereum network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/ethereum/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/ethereum/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/ethereum/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/ethereum/eth_syncing) - Check node sync progress

---

## rpc_modules - Ethereum RPC Method

# rpc_modules - Ethereum RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Ethereum endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/ethereum/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ethereum/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/ethereum/trace_transaction) - Trace namespace example

---

## trace_block - Ethereum RPC Method

# trace_block - Ethereum RPC Method

Returns traces for all transactions in a block on Ethereum.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Ethereum
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Ethereum chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/ethereum/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/ethereum/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/ethereum/trace_get) - Get a specific trace by index

---

## trace_call - Ethereum RPC Method

# trace_call - Ethereum RPC Method

Traces a call without creating a transaction on Ethereum, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Ethereum
- **Pre-execution analysis** - Test contract interactions without spending gas for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
        'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/ethereum/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/ethereum/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/ethereum/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Ethereum RPC Method

# trace_callMany - Ethereum RPC Method

Traces multiple calls in sequence on Ethereum, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Ethereum
- **Historical state comparison** - Compare how the same call would execute at different points in Ethereum chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}, ["trace"]],
      [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}, ["trace"]],
        [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045' }, ['trace']],
    [{ to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'}, ['trace']],
        [{'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/ethereum/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/ethereum/eth_call) - Execute call without trace

---

## trace_filter - Ethereum RPC Method

# trace_filter - Ethereum RPC Method

Returns traces matching a filter on Ethereum.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Ethereum
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/ethereum/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/ethereum/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/ethereum/eth_getLogs) - Filter event logs

---

## trace_get - Ethereum RPC Method

# trace_get - Ethereum RPC Method

Returns a trace at a specific position within a transaction on Ethereum.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Ethereum
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/ethereum/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/ethereum/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Ethereum RPC Method

# trace_replayBlockTransactions - Ethereum RPC Method

Replays all transactions in a block on Ethereum and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Ethereum
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Ethereum chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/ethereum/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/ethereum/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/ethereum/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Ethereum RPC Method

# trace_replayTransaction - Ethereum RPC Method

Replays a transaction on Ethereum and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Ethereum
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/ethereum/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/ethereum/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/ethereum/trace_block) - Get all traces in a block

---

## trace_transaction - Ethereum RPC Method

# trace_transaction - Ethereum RPC Method

Returns all traces for a specific transaction on Ethereum.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for DeFi protocols (60% market share), NFT marketplaces, DAOs, and enterprise dApps
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Ethereum
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x42690cc81dfd7f6a5ebc973fd8c4912e6068df47646c665a1b54fae904b0470a'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/ethereum/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/ethereum/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/ethereum/trace_filter) - Filter traces by criteria

---

## web3_clientVersion - Ethereum RPC Method

# web3_clientVersion - Ethereum RPC Method

Returns the current client software version string for your Ethereum node, including the client name, version number, OS, and runtime.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Ethereum client:', clientVersion);

// Using fetch
const response = await fetch('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Ethereum client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ethereum client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/ethereum/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ethereum/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/ethereum/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/ethereum/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Ethereum RPC Method

# web3_sha3 - Ethereum RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Ethereum.

> **Why Ethereum?** Build on the world's leading smart contract platform with the largest developer ecosystem with battle-tested security, institutional adoption, and unmatched ecosystem with $166B+ TVL.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, NFT creators, and enterprise blockchain teams:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/ethereum/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/ethereum/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/ethereum/web3_clientVersion) - Get node client version

---

## Etherlink RPC Documentation

# Etherlink RPC Documentation

## Etherlink RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Etherlink supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why build on Etherlink?

Etherlink runs Ethereum Virtual Machine (EVM) contracts on a Tezos Smart Rollup. Existing Solidity contracts and Ethereum tools can connect through its JSON-RPC interface. The native gas token is tez (XTZ).

Dwellir's mainnet nodes retain historical state. Use fixed block numbers to read balances, contract code, storage, and contract calls. You can also retrieve past blocks, receipts, and event logs.

## Quick start with Etherlink

Replace `YOUR_API_KEY` with your Dwellir API key. The WebSocket URL includes `/ws` after the key.

| Transport | Mainnet endpoint                                            |
| --------- | ----------------------------------------------------------- |
| HTTPS     | `https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY`  |
| WSS       | `wss://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY/ws` |

### Check the chain ID

Send a JSON-RPC request over HTTPS before using the endpoint in an application:

```bash
curl -X POST 'https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'
```

The result is `0xa729`, or **42793** in decimal.

### Read historical state

This ethers.js v6 example reads the native XTZ balance at block 1,000,000. Replace the address with the account you need to inspect.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY'
);
const network = await provider.getNetwork();
if (network.chainId !== 42793n) {
  throw new Error(`Expected Etherlink mainnet, received ${network.chainId}`);
}

const balance = await provider.getBalance(
  '0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b',
  1_000_000
);
console.log(balance.toString());
```

### Subscribe to new heads

Connect to the WebSocket URL shown above and send this message:

```json
{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
```

The response contains a subscription ID. Later `eth_subscription` notifications contain new block headers. Send `eth_unsubscribe` with that ID when you finish. Only `newHeads` subscriptions are verified here.

## Network specifications

| Parameter       | Value                                                 | Details                                   |
| --------------- | ----------------------------------------------------- | ----------------------------------------- |
| Chain ID        | 42793                                                 | Mainnet, hexadecimal `0xa729`             |
| Native currency | XTZ                                                   | Tez uses 18 decimals in the EVM interface |
| Network         | Tezos Smart Rollup                                    | EVM-compatible execution                  |
| Node client     | Octez EVM 0.66                                        | Dwellir mainnet archive nodes             |
| RPC transport   | HTTPS and WSS                                         | JSON-RPC 2.0; WSS uses the `/ws` path     |
| Explorer        | [Etherlink Explorer](https://explorer.etherlink.com/) | Mainnet blocks and transactions           |

## API reference

The reference pages use recorded mainnet requests with fixed block numbers, addresses, and transaction hashes. They document methods verified on Dwellir's Etherlink deployment.

## RPC capabilities and limits

| Capability              | Support               | Operational note                                                                                                                                  |
| ----------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Historical state        | Archive               | Read balances, code, storage, and calls at fixed block numbers                                                                                    |
| Event logs              | Supported             | Use [`eth_getLogs`](https://www.dwellir.com/docs/etherlink/eth_getLogs) with a block filter                                                                              |
| WebSocket subscriptions | `newHeads` verified   | Use the `/ws` endpoint and `eth_subscribe`                                                                                                        |
| Call traces             | `callTracer` verified | See [`debug_traceTransaction`](https://www.dwellir.com/docs/etherlink/debug_traceTransaction) and [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/etherlink/debug_traceBlockByNumber) |
| `eth_getProof`          | Unsupported           | Octez EVM 0.66 returns `-32004 Method not supported`                                                                                              |
| `eth_syncing`           | Unsupported           | Octez EVM 0.66 returns `-32004 Method not supported`                                                                                              |
| `net_peerCount`         | Unsupported           | Octez EVM 0.66 returns `-32004 Method not supported`                                                                                              |

### Trace availability

Etherlink mainnet block tracing starts at the Bifrost boundary, block **4,162,673**. Use `callTracer` with the verified debug methods. Earlier blocks have no call traces.

The examples use a `119s` timeout value. The endpoint accepted that value, but timeout enforcement was not verified. These examples do not establish support for other debug methods or tracers.

## Resources

- [Etherlink network](https://www.dwellir.com/networks/etherlink)
- [Top Etherlink RPC providers compared](https://www.dwellir.com/blog/top-etherlink-rpc-providers)
- [Authentication](https://www.dwellir.com/docs/getting-started/authentication)
- [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)
- [Etherlink EVM interface](https://docs.etherlink.com/evm/)
- [Etherlink endpoint support](https://docs.etherlink.com/evm/developing/endpoint-support/)
- [Etherlink tracing documentation](https://docs.etherlink.com/evm/developing/transactions/#tracing-transactions)

---

## debug_traceBlockByNumber - Etherlink RPC Method

# debug_traceBlockByNumber - Etherlink RPC Method

Traces all transactions in a block on Etherlink identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

Use callTracer. Mainnet block tracing starts at Bifrost block 4,162,673. The Dune client skips trace RPC below that height. Requests with timeout 119s succeeded; timeout enforcement was not verified.

## When to Use This Method

Read callTracer output for block 4,162,737. Mainnet block tracing starts at Bifrost block 4,162,673. Below that height, Dune skips trace RPC.

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Request Parameters

- `blockNumber` (`QUANTITY or TAG, required`): Block number in hexadecimal, or latest. Block tracing starts at 4,162,673.
- `tracerConfig` (`Object, required`): The verified configuration is {"tracer":"callTracer","timeout":"119s"}. Timeout enforcement was not verified.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 26,
  "method": "debug_traceBlockByNumber",
  "params": [
    "0x3f84b1",
    {
      "tracer": "callTracer",
      "timeout": "119s"
    }
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    {
      "txHash": "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",
      "result": {
        "type": "CALL",
        "from": "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
        "to": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
        "value": "0x00",
        "gas": "0x099520",
        "gasUsed": "0x02aeca",
        "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
        "output": "0x",
        "logs": [],
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0xfba31bfb2eb016968bc10726557fe72c1943b803",
            "value": "0x00",
            "gas": "0x09183b",
            "gasUsed": "0x02315b",
            "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
            "output": "0x",
            "logs": [],
            "calls": [
              {
                "type": "STATICCALL",
                "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
                "to": "0x0000000000000000000000000000000000000001",
                "value": "0x00",
                "gas": "0x08cfdb",
                "gasUsed": "0x0bb8",
                "input": "0x81f89130aced0b895c253b12f57bfe7ac8a511311c25e27e65139c6a4191397d000000000000000000000000000000000000000000000000000000000000001bdbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb1",
                "output": "0x0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de",
                "logs": [],
                "calls": []
              },
              {
                "type": "STATICCALL",
                "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
                "to": "0x0000000000000000000000000000000000000001",
                "value": "0x00",
                "gas": "0x08b1b0",
                "gasUsed": "0x0bb8",
                "input": "0x81f89130aced0b895c253b12f57bfe7ac8a511311c25e27e65139c6a4191397d000000000000000000000000000000000000000000000000000000000000001c3f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c3",
                "output": "0x0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774",
                "logs": [],
                "calls": []
              },
              {
                "type": "STATICCALL",
                "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
                "to": "0x0000000000000000000000000000000000000001",
                "value": "0x00",
                "gas": "0x0893f9",
                "gasUsed": "0x0bb8",
                "input": "0x2fb3f28ee9b92b0a5728fc21b6c7177499e8e2d47b5ad8b86ae0c82fcff93141000000000000000000000000000000000000000000000000000000000000001c0a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d53",
                "output": "0x00000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d202",
                "logs": [],
                "calls": []
              },
              {
                "type": "STATICCALL",
                "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
                "to": "0x0000000000000000000000000000000000000001",
                "value": "0x00",
                "gas": "0x087494",
                "gasUsed": "0x0bb8",
                "input": "0x385b54893657ac03c3b5b25c2890eac2b0d53a0f6bd60976bf10c82c3eccb0d3000000000000000000000000000000000000000000000000000000000000001b6a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e",
                "output": "0x000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be",
                "logs": [],
                "calls": []
              },
              {
                "type": "STATICCALL",
                "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
                "to": "0x0000000000000000000000000000000000000001",
                "value": "0x00",
                "gas": "0x085512",
                "gasUsed": "0x0bb8",
                "input": "0x3e5ae81a3e3b16e806e35927ed9a1a3b1dd74acade9faa43f980e89707411fa0000000000000000000000000000000000000000000000000000000000000001b51bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba463",
                "output": "0x0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de",
                "logs": [],
                "calls": []
              },
              {
                "type": "STATICCALL",
                "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
                "to": "0x0000000000000000000000000000000000000001",
                "value": "0x00",
                "gas": "0x08362d",
                "gasUsed": "0x0bb8",
                "input": "0x3e5ae81a3e3b16e806e35927ed9a1a3b1dd74acade9faa43f980e89707411fa0000000000000000000000000000000000000000000000000000000000000001b09c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe",
                "output": "0x0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774",
                "logs": [],
                "calls": []
              }
            ]
          }
        ]
      }
    }
  ],
  "id": 26
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":26,"method":"debug_traceBlockByNumber","params":["0x3f84b1",{"tracer":"callTracer","timeout":"119s"}]}'
```

---

## debug_traceTransaction - Etherlink RPC Method

# debug_traceTransaction - Etherlink RPC Method

Traces a transaction execution on Etherlink by transaction hash.

Use callTracer. Mainnet block tracing starts at Bifrost block 4,162,673. The Dune client skips trace RPC below that height. Requests with timeout 119s succeeded; timeout enforcement was not verified.

## When to Use This Method

Read callTracer output for the transaction recorded in block 4,162,737. The captured result contains a CALL and a nested call.

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash.
- `tracerConfig` (`Object, required`): The verified configuration is {"tracer":"callTracer","timeout":"119s"}. Timeout enforcement was not verified.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 9,
  "method": "debug_traceTransaction",
  "params": [
    "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",
    {
      "tracer": "callTracer",
      "timeout": "119s"
    }
  ]
}
```

## Response Fields

- `type` (`string, required`): Call type, such as CALL, DELEGATECALL, or STATICCALL
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided, in hexadecimal
- `gasUsed` (`string, required`): Gas consumed, in hexadecimal
- `input` (`string, required`): Call data
- `output` (`string, required`): Return data
- `value` (`string, required`): Value in wei, in hexadecimal
- `logs` (`array, required`): Logs in this trace entry
- `calls` (`array, required`): Nested calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": {
    "type": "CALL",
    "from": "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
    "to": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
    "value": "0x00",
    "gas": "0x099520",
    "gasUsed": "0x02aeca",
    "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
    "output": "0x",
    "logs": [],
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
        "to": "0xfba31bfb2eb016968bc10726557fe72c1943b803",
        "value": "0x00",
        "gas": "0x09183b",
        "gasUsed": "0x02315b",
        "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
        "output": "0x",
        "logs": [],
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0x0000000000000000000000000000000000000001",
            "value": "0x00",
            "gas": "0x08cfdb",
            "gasUsed": "0x0bb8",
            "input": "0x81f89130aced0b895c253b12f57bfe7ac8a511311c25e27e65139c6a4191397d000000000000000000000000000000000000000000000000000000000000001bdbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb1",
            "output": "0x0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de",
            "logs": [],
            "calls": []
          },
          {
            "type": "STATICCALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0x0000000000000000000000000000000000000001",
            "value": "0x00",
            "gas": "0x08b1b0",
            "gasUsed": "0x0bb8",
            "input": "0x81f89130aced0b895c253b12f57bfe7ac8a511311c25e27e65139c6a4191397d000000000000000000000000000000000000000000000000000000000000001c3f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c3",
            "output": "0x0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774",
            "logs": [],
            "calls": []
          },
          {
            "type": "STATICCALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0x0000000000000000000000000000000000000001",
            "value": "0x00",
            "gas": "0x0893f9",
            "gasUsed": "0x0bb8",
            "input": "0x2fb3f28ee9b92b0a5728fc21b6c7177499e8e2d47b5ad8b86ae0c82fcff93141000000000000000000000000000000000000000000000000000000000000001c0a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d53",
            "output": "0x00000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d202",
            "logs": [],
            "calls": []
          },
          {
            "type": "STATICCALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0x0000000000000000000000000000000000000001",
            "value": "0x00",
            "gas": "0x087494",
            "gasUsed": "0x0bb8",
            "input": "0x385b54893657ac03c3b5b25c2890eac2b0d53a0f6bd60976bf10c82c3eccb0d3000000000000000000000000000000000000000000000000000000000000001b6a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e",
            "output": "0x000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be",
            "logs": [],
            "calls": []
          },
          {
            "type": "STATICCALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0x0000000000000000000000000000000000000001",
            "value": "0x00",
            "gas": "0x085512",
            "gasUsed": "0x0bb8",
            "input": "0x3e5ae81a3e3b16e806e35927ed9a1a3b1dd74acade9faa43f980e89707411fa0000000000000000000000000000000000000000000000000000000000000001b51bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba463",
            "output": "0x0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de",
            "logs": [],
            "calls": []
          },
          {
            "type": "STATICCALL",
            "from": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
            "to": "0x0000000000000000000000000000000000000001",
            "value": "0x00",
            "gas": "0x08362d",
            "gasUsed": "0x0bb8",
            "input": "0x3e5ae81a3e3b16e806e35927ed9a1a3b1dd74acade9faa43f980e89707411fa0000000000000000000000000000000000000000000000000000000000000001b09c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe",
            "output": "0x0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774",
            "logs": [],
            "calls": []
          }
        ]
      }
    ]
  },
  "id": 9
}
```

## Tracer Options

These examples use `callTracer`. The `timeout: 119s` field was accepted. Timeout enforcement and other tracer options were not verified.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":9,"method":"debug_traceTransaction","params":["0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",{"tracer":"callTracer","timeout":"119s"}]}'
```

---

## eth_blockNumber - Etherlink RPC Method

# eth_blockNumber - Etherlink RPC Method

Returns the number of the most recent block on Etherlink.

## When to Use This Method

Read the current block height. The captured height is a recorded observation and changes as the node advances.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "eth_blockNumber",
  "params": []
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0x33f607f",
  "id": 2
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":2,"method":"eth_blockNumber","params":[]}'
```

---

## eth_call - Etherlink RPC Method

# eth_call - Etherlink RPC Method

Executes a new message call immediately without creating a transaction on Etherlink. Used for reading smart contract state.

## When to Use This Method

Read getPriceUnsafe(bytes32) on the Pyth proxy at block 4,162,675. This historical example skips freshness checks and is not a current trading price.

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Request Parameters

- `call` (`Object, required`): Call object with to and data for the historical Pyth getPriceUnsafe example.
- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 8,
  "method": "eth_call",
  "params": [
    {
      "to": "0x2880ab155794e7179c9ee2e38200202908c17b43",
      "data": "0x96834ad3e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
    },
    "0x3f8473"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0x000000000000000000000000000000000000000000000000000006ce3a4ea33600000000000000000000000000000000000000000000000000000000b7e490b1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000000000000000000000000000000000000000000000000000000672c90e9",
  "id": 8
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":8,"method":"eth_call","params":[{"to":"0x2880ab155794e7179c9ee2e38200202908c17b43","data":"0x96834ad3e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"},"0x3f8473"]}'
```

---

## eth_chainId - Etherlink RPC Method

# eth_chainId - Etherlink RPC Method

Returns the chain ID used for transaction signing on Etherlink.

## When to Use This Method

Identify Etherlink mainnet. The expected chain ID is 42793, hexadecimal 0xa729.

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_chainId",
  "params": []
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0xa729",
  "id": 1
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'
```

---

## eth_getBalance - Etherlink RPC Method

# eth_getBalance - Etherlink RPC Method

Returns the balance of a given address on Etherlink.

## When to Use This Method

Read the demonstrated account balance at block 1,000,000. The response is denominated in wei.

## Request Parameters

- `address` (`DATA, required`): 20-byte account or contract address.
- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 19,
  "method": "eth_getBalance",
  "params": [
    "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
    "0xf4240"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0x7200434edcab2b200",
  "id": 19
}
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":19,"method":"eth_getBalance","params":["0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b","0xf4240"]}'
```

---

## eth_getBlockByHash - Etherlink RPC Method

# eth_getBlockByHash - Etherlink RPC Method

Returns information about a block by hash on Etherlink.

## When to Use This Method

Read the same historical block using its recorded block hash.

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash.
- `fullTransactions` (`boolean, required`): True returns transaction objects, as shown in the verified example.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_getBlockByHash",
  "params": [
    "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
    true
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": {
    "number": "0x3f84b1",
    "hash": "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
    "parentHash": "0x3041ac8e04e37045be93ab6d430cf67ebe8a75523d140aadef9ed13683ed11b7",
    "nonce": "0x0000000000000000",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "transactionsRoot": "0xd8532881acefb82a19bc0d109500c508ddde0a48763e5133ef59241e682cdc08",
    "stateRoot": "0x73444ba45ab5365cefe6ab486a854fca252313dce78ddb290e16ea6bba162e76",
    "receiptsRoot": "0x89b630ea3cdbcd0950d8ba0421d266be4b2af2229806e9ae52a387ab4cef5a97",
    "miner": "0xcf02b9ca488f8f6f4e28e37aa1bdd16b3f1b2ad8",
    "difficulty": "0x0",
    "totalDifficulty": "0x0",
    "extraData": "0x",
    "size": "0x279",
    "gasLimit": "0x4000000000000",
    "gasUsed": "0x4564ea",
    "timestamp": "0x672c91fa",
    "transactions": [
      {
        "blockHash": "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
        "blockNumber": "0x3f84b1",
        "from": "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
        "gas": "0x4c4b40",
        "gasPrice": "0x3b9aca00",
        "hash": "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",
        "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
        "nonce": "0x1123fd",
        "to": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
        "transactionIndex": "0x0",
        "value": "0x0",
        "v": "0x14e76",
        "r": "0x98d3b2e5cff6d0a0facc6a13a2df8626aaccf1573d29e7b1d18521ba470d3a08",
        "s": "0x854b2712ea3568c5da1d7ab51d45c906e5f7f32b671bf69d56a03b2a1c7c9d9"
      }
    ],
    "uncles": [],
    "baseFeePerGas": "0x3b9aca00",
    "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
  },
  "id": 1
}
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByHash","params":["0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",true]}'
```

---

## eth_getBlockByNumber - Etherlink RPC Method

# eth_getBlockByNumber - Etherlink RPC Method

Returns information about a block by block number on Etherlink.

## When to Use This Method

Read the complete historical block at 4,162,737, including its transaction object.

## Request Parameters

- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.
- `fullTransactions` (`boolean, required`): True returns transaction objects, as shown in the verified example.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 22,
  "method": "eth_getBlockByNumber",
  "params": [
    "0x3f84b1",
    true
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": {
    "number": "0x3f84b1",
    "hash": "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
    "parentHash": "0x3041ac8e04e37045be93ab6d430cf67ebe8a75523d140aadef9ed13683ed11b7",
    "nonce": "0x0000000000000000",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "transactionsRoot": "0xd8532881acefb82a19bc0d109500c508ddde0a48763e5133ef59241e682cdc08",
    "stateRoot": "0x73444ba45ab5365cefe6ab486a854fca252313dce78ddb290e16ea6bba162e76",
    "receiptsRoot": "0x89b630ea3cdbcd0950d8ba0421d266be4b2af2229806e9ae52a387ab4cef5a97",
    "miner": "0xcf02b9ca488f8f6f4e28e37aa1bdd16b3f1b2ad8",
    "difficulty": "0x0",
    "totalDifficulty": "0x0",
    "extraData": "0x",
    "size": "0x279",
    "gasLimit": "0x4000000000000",
    "gasUsed": "0x4564ea",
    "timestamp": "0x672c91fa",
    "transactions": [
      {
        "blockHash": "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
        "blockNumber": "0x3f84b1",
        "from": "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
        "gas": "0x4c4b40",
        "gasPrice": "0x3b9aca00",
        "hash": "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",
        "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
        "nonce": "0x1123fd",
        "to": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
        "transactionIndex": "0x0",
        "value": "0x0",
        "v": "0x14e76",
        "r": "0x98d3b2e5cff6d0a0facc6a13a2df8626aaccf1573d29e7b1d18521ba470d3a08",
        "s": "0x854b2712ea3568c5da1d7ab51d45c906e5f7f32b671bf69d56a03b2a1c7c9d9"
      }
    ],
    "uncles": [],
    "baseFeePerGas": "0x3b9aca00",
    "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
  },
  "id": 22
}
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":22,"method":"eth_getBlockByNumber","params":["0x3f84b1",true]}'
```

---

## eth_getBlockReceipts - Etherlink RPC Method

# eth_getBlockReceipts - Etherlink RPC Method

Returns all transaction receipts for a block on Etherlink. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

## When to Use This Method

Read every transaction receipt at block 4,162,675. The captured receipt contains five event logs.

## Request Parameters

- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 12,
  "method": "eth_getBlockReceipts",
  "params": [
    "0x3f8473"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    {
      "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
      "transactionIndex": "0x0",
      "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
      "blockNumber": "0x3f8473",
      "from": "0x9f53ea2532fcc50f31ec587e4a441e4ad72f4b8c",
      "to": "0x2880ab155794e7179c9ee2e38200202908c17b43",
      "cumulativeGasUsed": "0xc434af",
      "effectiveGasPrice": "0x3b9aca00",
      "gasUsed": "0xc434af",
      "logs": [
        {
          "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
          "topics": [
            "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
            "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
          ],
          "data": "0x00000000000000000000000000000000000000000000000000000000672c90e9000000000000000000000000000000000000000000000000000006ce3a4ea33600000000000000000000000000000000000000000000000000000000b7e490b1",
          "blockNumber": "0x3f8473",
          "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
          "transactionIndex": "0x0",
          "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
          "logIndex": "0x0",
          "removed": false
        },
        {
          "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
          "topics": [
            "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
            "0x0affd4b8ad136a21d79bc82450a325ee12ff55a235abc242666e423b8bcffd03"
          ],
          "data": "0x00000000000000000000000000000000000000000000000000000000672c90e90000000000000000000000000000000000000000000000000000000003dc109b00000000000000000000000000000000000000000000000000000000000260c7",
          "blockNumber": "0x3f8473",
          "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
          "transactionIndex": "0x0",
          "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
          "logIndex": "0x1",
          "removed": false
        },
        {
          "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
          "topics": [
            "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
            "0x9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6"
          ],
          "data": "0x00000000000000000000000000000000000000000000000000000000672c90e9000000000000000000000000000000000000000000000000000000418909550e000000000000000000000000000000000000000000000000000000003ac1044c",
          "blockNumber": "0x3f8473",
          "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
          "transactionIndex": "0x0",
          "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
          "logIndex": "0x2",
          "removed": false
        },
        {
          "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
          "topics": [
            "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
            "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a"
          ],
          "data": "0x00000000000000000000000000000000000000000000000000000000672c90e90000000000000000000000000000000000000000000000000000000005f5c1c00000000000000000000000000000000000000000000000000000000000011170",
          "blockNumber": "0x3f8473",
          "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
          "transactionIndex": "0x0",
          "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
          "logIndex": "0x3",
          "removed": false
        },
        {
          "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
          "topics": [
            "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
            "0x2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b"
          ],
          "data": "0x00000000000000000000000000000000000000000000000000000000672c90e90000000000000000000000000000000000000000000000000000000005f670e6000000000000000000000000000000000000000000000000000000000001ab41",
          "blockNumber": "0x3f8473",
          "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
          "transactionIndex": "0x0",
          "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
          "logIndex": "0x4",
          "removed": false
        }
      ],
      "logsBloom": "0x00000000000000000200202000000000000000000000000000000000000000000200000000000000000000000008000000000200000000000000000000000000000000000000000000400000000010000000001000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000004000000000000000000000000000000000000000000000000010000040000000010001000000000000000000000000000000000000000040000000000000000000000000000002000000000000000000000000000000000000000000000100008000000000800000000000",
      "type": "0x0",
      "status": "0x1",
      "contractAddress": null
    }
  ],
  "id": 12
}
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":12,"method":"eth_getBlockReceipts","params":["0x3f8473"]}'
```

---

## eth_getCode - Etherlink RPC Method

# eth_getCode - Etherlink RPC Method

Returns the bytecode at a given address on Etherlink.

## When to Use This Method

Read the Pyth implementation contract code at block 4,162,675. The captured result contains 20,568 bytes.

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Request Parameters

- `address` (`DATA, required`): 20-byte account or contract address.
- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "eth_getCode",
  "params": [
    "0xa2aa501b19aff244d90cc15a4cf739d2725b5729",
    "0x3f8473"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0x6080604052600436106102725760003560e01c80638881016f1161014f578063b5ec0261116100c1578063d82d58a51161007a578063d82d58a514610819578063e17efd4814610852578063e18910a314610872578063e3795cc114610887578063ef9e5e281461089e578063f2fde38b146108b157600080fd5b8063b5ec02611461074c578063b6ed701e14610784578063b9256d28146107a4578063caaf43f1146107b7578063cb718a9b146107e4578063d47eed45146107f957600080fd5b80639a8a0592116101135780639a8a0592146106af578063a38d81c6146106d7578063a4ae35e0146106f9578063aac41292146105f9578063accca7f914610719578063b5dcc9111461072c57600080fd5b80638881016f146105f957806389a5bb4d146106315780638da5cb5b146106515780639474f45b1461066f57806396834ad31461068f57600080fd5b806352d1902d116101e85780636c72f51b116101ac5780636c72f51b14610504578063711a2e2814610530578063715018a6146105505780637b72bcae1461056557806384acd1bb1461059a57806387c5bd1b146105cc57600080fd5b806352d1902d1461045057806354fd4d5014610465578063586d3cf81461049957806358c67635146104b75780636b7f53ca146104d757600080fd5b8063437209a71161023a578063437209a7146103605780634716e9c51461039057806348b6404d146103b05780634c469d8c146103cf5780634d7a734e1461041d5780634f1ef2861461043d57600080fd5b8063146faf771461027757806314dd317f1461029957806331d98b3f146102cd5780633659cfe6146102fa578063426234e41461031a575b600080fd5b34801561028357600080fd5b50610297610292366004614351565b6108d1565b005b3480156102a557600080fd5b506102b96102b436600461467e565b610a13565b604051905181526020015b60405180910390f35b3480156102d957600080fd5b506102ed6102e83660046145c1565b610a6d565b6040516102c49190614c91565b34801561030657600080fd5b50610297610315366004614337565b610a87565b34801561032657600080fd5b506040805180820182526000808252602091820152815180830190925260d05461ffff16825260d154908201526040516102c49190614c06565b34801561036c57600080fd5b5061038061037b36600461488f565b610b6d565b60405190151581526020016102c4565b6103a361039e366004614530565b610bc0565b6040516102c49190614a77565b3480156103bc57600080fd5b5060ce545b6040519081526020016102c4565b3480156103db57600080fd5b506104056103ea3660046145c1565b600090815260d560205260409020546001600160401b031690565b6040516001600160401b0390911681526020016102c4565b34801561042957600080fd5b506102b961043836600461467e565b610c09565b61029761044b366004614411565b610ca1565b34801561045c57600080fd5b506103c1610d5b565b34801561047157600080fd5b506040805180820182526005815264312e342e3360d81b602082015290516102c49190614af5565b3480156104a557600080fd5b5060d2546001600160401b0316610405565b3480156104c357600080fd5b506103806104d236600461488f565b610e0e565b3480156104e357600080fd5b506104f76104f236600461467e565b610e31565b6040516102c49190614c21565b34801561051057600080fd5b5060d45463ffffffff165b60405163ffffffff90911681526020016102c4565b34801561053c57600080fd5b506102ed61054b3660046145f1565b611035565b34801561055c57600080fd5b50610297611076565b34801561057157600080fd5b5061058561058036600461467e565b61108a565b604051905163ffffffff1681526020016102c4565b3480156105a657600080fd5b5060c9546001600160a01b03165b6040516001600160a01b0390911681526020016102c4565b3480156105d857600080fd5b506105ec6105e736600461467e565b6110b8565b6040516102c49190614ccb565b34801561060557600080fd5b5061061961061436600461467e565b611234565b60405190516001600160a01b031681526020016102c4565b34801561063d57600080fd5b506103c161064c3660046146b0565b611265565b34801561065d57600080fd5b506033546001600160a01b03166105b4565b34801561067b57600080fd5b506102ed61068a3660046145c1565b6112b7565b34801561069b57600080fd5b506102ed6106aa3660046145c1565b611338565b3480156106bb57600080fd5b506106c46113bd565b60405161ffff90911681526020016102c4565b3480156106e357600080fd5b506106ec611446565b6040516102c49190614a3f565b34801561070557600080fd5b506102ed6107143660046145f1565b6114b9565b6103a3610727366004614530565b6114ca565b34801561073857600080fd5b506102ed6107473660046145c1565b611508565b34801561075857600080fd5b506103806107673660046145c1565b600090815260d560205260409020546001600160401b0316151590565b34801561079057600080fd5b5061029761079f366004614612565b61151c565b6102976107b236600461449b565b611836565b3480156107c357600080fd5b506107d76107d23660046145c1565b61192d565b6040516102c49190614c82565b3480156107f057600080fd5b5060cf546103c1565b34801561080557600080fd5b506103c161081436600461445c565b6119fb565b34801561082557600080fd5b5061084561083436600461467e565b604080516020810190915290815290565b6040516102c49190614beb565b34801561085e57600080fd5b506103c161086d3660046145c1565b611ba2565b34801561087e57600080fd5b506103c1611bc3565b34801561089357600080fd5b506397a6f30461051b565b6102976108ac36600461445c565b611bce565b3480156108bd57600080fd5b506102976108cc366004614337565b611c59565b600054610100900460ff16158080156108f15750600054600160ff909116105b8061090b5750303b15801561090b575060005460ff166001145b6109735760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610996576000805461ff0019166101001790555b61099e611cde565b6109a6611d0d565b6109b88b8b8b8b8b8b8b8b8b8b611d34565b6109c0611076565b8015610a06576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050505050565b6040805160208101909152600081526000610a2e8382611f1c565b6001600160401b03168252610a44600882614df4565b905080835114610a67576040516397363b3560e01b815260040160405180910390fd5b50919050565b610a7561400d565b610a8182610714611bc3565b92915050565b306001600160a01b037f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b5729161415610ad05760405162461bcd60e51b815260040161096a90614b08565b7f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b57296001600160a01b0316610b02611f79565b6001600160a01b031614610b285760405162461bcd60e51b815260040161096a90614b54565b610b3181611f95565b610b6a8160005b6040519080825280601f01601f191660200182016040528015610b62576020820181803683370190505b506000611f9d565b50565b6040805160f09390931b6001600160f01b0319166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b6060610bfe878787876040518060600160405280896001600160401b03168152602001886001600160401b031681526020016000151581525061211c565b979650505050505050565b604080516020810190915260008152600080610c258482611f1c565b9050610c32600883614df4565b91506000610c408584611f1c565b9050610c4d600884614df4565b9250610c636001600160401b038216600a614e4f565b610c76906001600160401b038416614ef7565b845284518314610c99576040516397363b3560e01b815260040160405180910390fd5b505050919050565b306001600160a01b037f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b5729161415610cea5760405162461bcd60e51b815260040161096a90614b08565b7f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b57296001600160a01b0316610d1c611f79565b6001600160a01b031614610d425760405162461bcd60e51b815260040161096a90614b54565b610d4b82611f95565b610d5782826001611f9d565b5050565b6000306001600160a01b037f000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b57291614610dfb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161096a565b50600080516020614fdc83398151915290565b60d05460009061ffff8481169116148015610e2a575060d15482145b9392505050565b610e5d604080516080810190915280600081526020016000815260006020820152606060409091015290565b600080610e6a8482612477565b905063ffffffff8116635054474d14610e96576040516397363b3560e01b815260040160405180910390fd5b610ea1600483614df4565b91506000610eaf85846124d4565b90508060ff166003811115610ed457634e487b7160e01b600052602160045260246000fd5b84906003811115610ef557634e487b7160e01b600052602160045260246000fd5b90816003811115610f1657634e487b7160e01b600052602160045260246000fd5b905250610f24600184614df4565b9250600184516003811115610f4957634e487b7160e01b600052602160045260246000fd5b14610f67576040516363daeb7760e01b815260040160405180910390fd5b6000610f7386856124d4565b90508060ff166006811115610f9857634e487b7160e01b600052602160045260246000fd5b85602001906006811115610fbc57634e487b7160e01b600052602160045260246000fd5b90816006811115610fdd57634e487b7160e01b600052602160045260246000fd5b905250610feb600185614df4565b9350610ff78685612530565b61ffff16604086015261100b600285614df4565b93506110268485885161101e9190614f16565b88919061258d565b60608601525092949350505050565b61103d61400d565b611046836112b7565b90508161105742836060015161269a565b1115610a8157604051630cd5fa0760e11b815260040160405180910390fd5b61107e6126bf565b6110886000612719565b565b60408051602081019091526000815260006110a58382612477565b63ffffffff168252610a44600482614df4565b6040805160208101909152606081526000806110d484826124d4565b90506110e1600183614df4565b91508060ff166001600160401b0381111561110c57634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561115157816020015b604080518082019091526000808252602082015281526020019060019003908161112a5790505b50835260005b8160ff1681101561120b5761116c8584612530565b845180518390811061118e57634e487b7160e01b600052603260045260246000fd5b602090810291909101015161ffff90911690526111ac600284614df4565b92506111b8858461276b565b84518051839081106111da57634e487b7160e01b600052603260045260246000fd5b602002602001015160200181815250506020836111f79190614df4565b92508061120381614f59565b915050611157565b508184511461122d576040516397363b3560e01b815260040160405180910390fd5b5050919050565b604080516020810190915260008152600061124f83826127c9565b6001600160a01b03168252610a44601482614df4565b60008160000151826020015160405160200161129a92919060f09290921b6001600160f01b0319168252600282015260220190565b604051602081830303815290604052805190602001209050919050565b6112bf61400d565b600082815260d5602090815260409182902080546001600160401b0380821660608701819052600160401b92839004600390810b810b900b958701959095526001830154600781810b810b900b875291909104169184019190915290610a6757604051630295d7cd60e31b815260040160405180910390fd5b61134061400d565b600082815260d5602090815260409182902080546001600160401b0380821660608701819052600160401b8304600390810b810b900b95870195909552600160601b8204600790810b810b900b8652600160a01b909104169184019190915290610a6757604051630295d7cd60e31b815260040160405180910390fd5b60006113d160c9546001600160a01b031690565b6001600160a01b0316639a8a05926040518163ffffffff1660e01b815260040160206040518083038186803b15801561140957600080fd5b505afa15801561141d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114419190614873565b905090565b606060c9600301805480602002602001604051908101604052809291908181526020016000905b828210156114b05760008481526020908190206040805180820190915260028502909101805461ffff16825260019081015482840152908352909201910161146d565b50505050905090565b6114c161400d565b61104683611338565b6060610bfe878787876040518060600160405280896001600160401b03168152602001886001600160401b031681526020016001151581525061211c565b61151061400d565b610a818261054b611bc3565b600061155d83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061282e92505050565b9050600061156e8260e00151610e31565b90506115786113bd565b61ffff16816040015161ffff161415801561159a5750604081015161ffff1615155b156115b8576040516363daeb7760e01b815260040160405180910390fd5b6000816020015160068111156115de57634e487b7160e01b600052602160045260246000fd5b141561162457604081015161ffff1661160a576040516363daeb7760e01b815260040160405180910390fd5b61161f61161a8260600151611234565b612971565b611830565b60018160200151600681111561164a57634e487b7160e01b600052602160045260246000fd5b14156116715761161f61166c8260600151604080516020810190915290815290565b61297a565b60028160200151600681111561169757634e487b7160e01b600052602160045260246000fd5b14156116b25761161f6116ad82606001516110b8565b612c56565b6003816020015160068111156116d857634e487b7160e01b600052602160045260246000fd5b14156116f35761161f6116ee8260600151610c09565b612dff565b60048160200151600681111561171957634e487b7160e01b600052602160045260246000fd5b14156117345761161f61172f8260600151610a13565b612e51565b60058160200151600681111561175a57634e487b7160e01b600052602160045260246000fd5b1415611779576040516397363b3560e01b815260040160405180910390fd5b60068160200151600681111561179f57634e487b7160e01b600052602160045260246000fd5b141561181757604081015161ffff166117cb576040516363daeb7760e01b815260040160405180910390fd5b61161f6117db8260600151611234565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612e8e92505050565b6040516397363b3560e01b815260040160405180910390fd5b50505050565b8281146118565760405163a9cb9e0d60e01b815260040160405180910390fd5b60005b8381101561190b5782828281811061188157634e487b7160e01b600052603260045260246000fd5b905060200201602081019061189691906148d4565b6001600160401b03166118e48686848181106118c257634e487b7160e01b600052603260045260246000fd5b90506020020135600090815260d560205260409020546001600160401b031690565b6001600160401b03161015611903576118fd8787611bce565b50611925565b600101611859565b50604051636f162bfd60e11b815260040160405180910390fd5b505050505050565b611935614034565b6000611940836130c2565b80519091506001600160401b031661196b57604051630295d7cd60e31b815260040160405180910390fd5b91815260408083015160208084018051600793840b840b905260608087015182516001600160401b039182169085015283880180518451600391820b820b9089015289519451948316948401949094526080890151878901805191880b90970b905260a089015186519083169501949094529251845190830b90920b919094015293519051931692019190915290565b600080805b83811015611b90576004858583818110611a2a57634e487b7160e01b600052603260045260246000fd5b9050602002810190611a3c9190614ce6565b9050118015611a90575063504e4155611a88868684818110611a6e57634e487b7160e01b600052603260045260246000fd5b9050602002810190611a809190614ce6565b503560e01c90565b63ffffffff16145b15611b6557600080611ad2878785818110611abb57634e487b7160e01b600052603260045260246000fd5b9050602002810190611acd9190614ce6565b613154565b90925090506000818015611af657634e487b7160e01b600052602160045260246000fd5b14611b145760405163734fff6760e11b815260040160405180910390fd5b611b4f878785818110611b3757634e487b7160e01b600052603260045260246000fd5b9050602002810190611b499190614ce6565b8461321b565b611b5c9060ff1685614df4565b93505050611b7e565b60405163734fff6760e11b815260040160405180910390fd5b80611b8881614f59565b915050611a00565b50611b9a81613252565b949350505050565b600081611bae60ce5490565b611bb99060ff614ef7565b610a819190614ef7565b600061144160cf5490565b6000805b82811015611c2b57611c14848483818110611bfd57634e487b7160e01b600052603260045260246000fd5b9050602002810190611c0f9190614ce6565b613267565b611c219060ff1683614df4565b9150600101611bd2565b506000611c3782613252565b9050803410156118305760405162976f7560e21b815260040160405180910390fd5b611c616126bf565b6001600160a01b038116611cc65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161096a565b610b6a81612719565b6001600160a01b03163b151590565b600054610100900460ff16611d055760405162461bcd60e51b815260040161096a90614ba0565b611088613348565b600054610100900460ff166110885760405162461bcd60e51b815260040161096a90614ba0565b611d3d8a613378565b878614611d5d5760405163a9cb9e0d60e01b815260040160405180910390fd5b60005b88811015611ec757600060405180604001604052808c8c85818110611d9557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611daa9190614857565b61ffff1681526020018a8a85818110611dd357634e487b7160e01b600052603260045260246000fd5b905060200201358152509050611df181600001518260200151610b6d565b15611e0f5760405163a9cb9e0d60e01b815260040160405180910390fd5b600160cd6000611e1e84611265565b81526020808201929092526040016000908120805460ff19169315159390931790925560cc8054600181018255925282517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebe6002909302928301805461ffff191661ffff90921691909117905591909101517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebf9091015580611ebf81614f59565b915050611d60565b506040805180820190915261ffff86168082526020820186905260d0805461ffff1916909117905560d1859055611efd8461339a565b50611f078260cf55565b611f108160ce55565b50505050505050505050565b6000611f29826008614df4565b83511015611f705760405162461bcd60e51b8152602060048201526014602482015273746f55696e7436345f6f75744f66426f756e647360601b604482015260640161096a565b50016008015190565b600080516020614fdc833981519152546001600160a01b031690565b610b6a6126bf565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611fd557611fd0836133bd565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561200e57600080fd5b505afa92505050801561203e575060408051601f3d908101601f1916820190925261203b918101906145d9565b60015b6120a15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840161096a565b600080516020614fdc83398151915281146121105760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840161096a565b50611fd0838383613459565b6060600061212a87876119fb565b90508034101561214c5760405162976f7560e21b815260040160405180910390fd5b50826001600160401b0381111561217357634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156121ac57816020015b612199614034565b8152602001906001900390816121915790505b50905060005b858110156124105760048787838181106121dc57634e487b7160e01b600052603260045260246000fd5b90506020028101906121ee9190614ce6565b9050118015612228575063504e4155612220888884818110611a6e57634e487b7160e01b600052603260045260246000fd5b63ffffffff16145b15611b6557600080612253898985818110611abb57634e487b7160e01b600052603260045260246000fd5b9092509050600081801561227757634e487b7160e01b600052602160045260246000fd5b146122955760405163734fff6760e11b815260040160405180910390fd5b506000803660006122d78c8c888181106122bf57634e487b7160e01b600052603260045260246000fd5b90506020028101906122d19190614ce6565b8761347e565b93985091965094509250905060005b8360ff168110156123e2576122f9614061565b6000806123088887878c6135c0565b929b509094509250905061231c8284613696565b60006123298f8f856137d8565b90508d81148061236357508b818151811061235457634e487b7160e01b600052603260045260246000fd5b60209081029190910101515115155b1561237157505050506123da565b83518d516001600160401b039182169116811080159061239e57508d602001516001600160401b03168111155b80156123c257508d6040015115806123c257508d516001600160401b038085169116115b156123d4576123d48d83868885613829565b50505050505b6001016122e6565b508481146124035760405163734fff6760e11b815260040160405180910390fd5b50505050506001016121b2565b5060005b8381101561246d5781818151811061243c57634e487b7160e01b600052603260045260246000fd5b602090810291909101015151612465576040516345805f5d60e01b815260040160405180910390fd5b600101612414565b5095945050505050565b6000612484826004614df4565b835110156124cb5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7433325f6f75744f66426f756e647360601b604482015260640161096a565b50016004015190565b60006124e1826001614df4565b835110156125275760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b604482015260640161096a565b50016001015190565b600061253d826002614df4565b835110156125845760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640161096a565b50016002015190565b60608161259b81601f614df4565b10156125da5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640161096a565b6125e48284614df4565b845110156126285760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640161096a565b6060821580156126475760405191506000825260208201604052612691565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612680578051835260209283019201612668565b5050858452601f01601f1916604052505b50949350505050565b6000818311156126b5576126ae8284614f16565b9050610a81565b6126ae8383614f16565b6033546001600160a01b031633146110885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161096a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612778826020614df4565b835110156127c05760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b604482015260640161096a565b50016020015190565b60006127d6826014614df4565b8351101561281e5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b604482015260640161096a565b500160200151600160601b900490565b612836614096565b60008061284b60c9546001600160a01b031690565b6001600160a01b031663c0fd8bde856040518263ffffffff1660e01b81526004016128769190614af5565b60006040518083038186803b15801561288e57600080fd5b505afa1580156128a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128ca9190810190614706565b5091509150806128ed57604051632acbe91560e01b815260040160405180910390fd5b6128ff82606001518360800151610e0e565b61291c5760405163360f2d8760e01b815260040160405180910390fd5b60d2546001600160401b03166001600160401b03168260a001516001600160401b03161161295d576040516388d1b84760e01b815260040160405180910390fd5b61296a8260a0015161339a565b5092915050565b610b6a81613a69565b60006129ae6040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b90506000806129c560c9546001600160a01b031690565b845160405163607ec5ef60e11b81526001600160a01b03929092169163c0fd8bde916129f391600401614af5565b60006040518083038186803b158015612a0b57600080fd5b505afa158015612a1f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a479190810190614706565b509150915080612a6a57604051632acbe91560e01b815260040160405180910390fd5b6000612a798360e00151610e31565b9050612a836113bd565b61ffff16816040015161ffff1614158015612aa55750604081015161ffff1615155b15612ac3576040516363daeb7760e01b815260040160405180910390fd5b600581602001516006811115612ae957634e487b7160e01b600052602160045260246000fd5b14612b07576040516397363b3560e01b815260040160405180910390fd5b6000612b16826060015161108a565b805190915063ffffffff16612b3060d45463ffffffff1690565b63ffffffff1610612b54576040516388d1b84760e01b815260040160405180910390fd5b805160d4805463ffffffff191663ffffffff90921691909117905560408051808201909152606085015161ffff1680825260808601516020830181905260d0805461ffff191690921790915560d155612bb08560a0015161339a565b7f6bce23ef3d34e51710fe4700b43ba5f1733a6215c883f384671a4ece3ea8aa2086612c046040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b60d25460408051845161ffff90811682526020958601518683015284511691810191909152929091015160608301526001600160401b0316608082015260a0015b60405180910390a150505050505050565b6000612c60611446565b905060005b8151811015612cd857600060c96004016000612ca7858581518110612c9a57634e487b7160e01b600052603260045260246000fd5b6020026020010151611265565b81526020810191909152604001600020805460ff1916911515919091179055612cd1600182614df4565b9050612c65565b50612ce560cc60006140f1565b60005b825151811015612dba578251805160cc919083908110612d1857634e487b7160e01b600052603260045260246000fd5b60209081029190910181015182546001808201855560009485528385208351600290930201805461ffff191661ffff90931692909217825591909201519181019190915584518051919260cd929091612d899186908110612c9a57634e487b7160e01b600052603260045260246000fd5b81526020810191909152604001600020805460ff191691151591909117905580612db281614f59565b915050612ce8565b507fd451e0fcb7c5b9e13de533604d158069dad159841c45f39f09d379bfc423080d81612de5611446565b604051612df3929190614a52565b60405180910390a15050565b6000612e0a60ce5490565b825160ce5590507f74dbbbe280ef27b79a8a0c449d5ae2ba7a31849103241d0f98df70bbc9d03e3781612e3c60ce5490565b60408051928352602083019190915201612df3565b6000612e5c60cf5490565b825160cf5590507fcdb88a22f82ddd76115ab7c66cf08eb1e40afe80c9b31017eb2cbdb1570b33ae81612e3c60cf5490565b6000612ea260c9546001600160a01b031690565b9050612eb18360000151613378565b600080612ec660c9546001600160a01b031690565b6001600160a01b031663c0fd8bde856040518263ffffffff1660e01b8152600401612ef19190614af5565b60006040518083038186803b158015612f0957600080fd5b505afa158015612f1d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f459190810190614706565b509150915080612f68576040516397363b3560e01b815260040160405180910390fd5b612f7a82606001518360800151610e0e565b612f97576040516397363b3560e01b815260040160405180910390fd5b60d2546001600160401b03166001600160401b03168260a001516001600160401b031614612fd8576040516309e9f6c160e11b815260040160405180910390fd5b6000612fe78360e00151610e31565b905060068160200151600681111561300f57634e487b7160e01b600052602160045260246000fd5b1461302d576040516309e9f6c160e11b815260040160405180910390fd5b600061303c8260600151611234565b875181519192506001600160a01b0391821691161461306e576040516309e9f6c160e11b815260040160405180910390fd5b7fd495c4e5b386d59bccca38a2277b5d70a0f5e47d7b6587a45a6f5aca221a3125856130a260c9546001600160a01b031690565b604080516001600160a01b03938416815292909116602083015201612c45565b6130ca614061565b50600090815260d56020908152604091829020825160c08101845281546001600160401b038082168352600160401b808304600390810b810b900b95840195909552600160601b8204600790810b810b810b96840196909652600160a01b9091048116606083015260019092015480850b850b90940b60808201529190920490911660a082015290565b60046000833560e01c63504e415581146131815760405163734fff6760e11b815260040160405180910390fd5b60018084019386013560f81c9081146131ad5760405163734fff6760e11b815260040160405180910390fd5b50508184016001013560f890811c9092016002818101939186010135901c60ff1680156131ea57634e487b7160e01b600052602160045260246000fd5b600192909201919050818310156132145760405163734fff6760e11b815260040160405180910390fd5b9250929050565b60008382013560f01c61322f600284614df4565b925061323f61ffff821684614df4565b92508483013560f81c5b95945050505050565b600061325d60ce5490565b610a819083614ef7565b60008060006132768585613154565b9092509050600081801561329a57634e487b7160e01b600052602160045260246000fd5b146132b85760405163734fff6760e11b815260040160405180910390fd5b6000803660006132c989898861347e565b919a50929650909450909250905060005b8760ff1681101561331b576132ed614061565b6000806132fc8787878b6135c0565b929a50909450925090506133108284613696565b5050506001016132da565b5083811461333c5760405163734fff6760e11b815260040160405180910390fd5b50505050505092915050565b600054610100900460ff1661336f5760405162461bcd60e51b815260040161096a90614ba0565b61108833612719565b60c980546001600160a01b0319166001600160a01b0392909216919091179055565b60d2805467ffffffffffffffff19166001600160401b0392909216919091179055565b6001600160a01b0381163b61342a5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161096a565b600080516020614fdc83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61346283613b67565b60008251118061346f5750805b15611fd0576118308383613ba7565b600080803681613492888888808203613c92565b600296509092509050813560f01c606060006134b86134b386868b87613c92565b613cbc565b60e0015160048082015161ffff86169a909a01999193509150634155575663ffffffff8216146134fb5760405163734fff6760e11b815260040160405180910390fd5b8183016001015160009060ff16801561352457634e487b7160e01b600052602160045260246000fd5b6001909301929050600081801561354b57634e487b7160e01b600052602160045260246000fd5b146135695760405163734fff6760e11b815260040160405180910390fd5b602c84840101518451600160601b90910460601b99506020909301928311156135a55760405163734fff6760e11b815260040160405180910390fd5b5050600188019b969a505050509381013560f81c9550935050565b60006135ca614061565b600283019260009081903690829089013560f01c6135ea8a8a8a84613c92565b925092508061ffff168801975060006136078b8b8b8f8888613dad565b98509050806136295760405163734fff6760e11b815260040160405180910390fd5b6000843560f81c801561364c57634e487b7160e01b600052602160045260246000fd5b9050600081801561366d57634e487b7160e01b600052602160045260246000fd5b1415611b655761367f85856001613e55565b919950975095505050505050945094509450949050565b600082815260d5602052604090205481516001600160401b039182169116811015611fd057600083815260d560209081526040918290208451815486840151878601516060808a01516001600160401b039586166001600160601b03199095168517600160401b63ffffffff60039690960b959095168502176fffffffffffffffffffffffffffffffff60601b1916600160601b600794850b8089169190910267ffffffffffffffff60a01b191691909117600160a01b92881692830217885560808c01516001909801805460a08e01519990950b88166fffffffffffffffffffffffffffffffff1990951694909417979096169093029590951790558551918252938101919091529283019190915284917fd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec910160405180910390a2505050565b6000805b83811015611b9a578285858381811061380557634e487b7160e01b600052603260045260246000fd5b90506020020135141561381757611b9a565b8061382181614f59565b9150506137dc565b8285858151811061384a57634e487b7160e01b600052603260045260246000fd5b60200260200101516000018181525050816040015185858151811061387f57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516000019060070b908160070b8152505081606001518585815181106138c057634e487b7160e01b600052603260045260246000fd5b602002602001015160200151602001906001600160401b031690816001600160401b031681525050816020015185858151811061390d57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040019060030b908160030b815250508085858151811061394a57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516060018181525050816080015185858151811061398357634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516000019060070b908160070b815250508160a001518585815181106139c457634e487b7160e01b600052603260045260246000fd5b602002602001015160400151602001906001600160401b031690816001600160401b0316815250508160200151858581518110613a1157634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516040019060030b908160030b8152505080858581518110613a4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516040015160600181815250505050505050565b6000613a73611f79565b8251909150613a83906000610b38565b306001600160a01b031663e3795cc16040518163ffffffff1660e01b815260040160206040518083038186803b158015613abc57600080fd5b505afa158015613ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af491906148ba565b63ffffffff166397a6f30414613b1d576040516397363b3560e01b815260040160405180910390fd5b7f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a4981613b47611f79565b604080516001600160a01b03938416815292909116602083015201612df3565b613b70816133bd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613c0f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161096a565b600080846001600160a01b031684604051613c2a91906149f4565b600060405180830381855af49150503d8060008114613c65576040519150601f19603f3d011682016040523d82523d6000602084013e613c6a565b606091505b50915091506132498282604051806060016040528060278152602001614ffc60279139613f43565b366000858486613ca28683614df4565b92613caf93929190614dcc565b9150915094509492505050565b613cc4614096565b6000613cd860c9546001600160a01b031690565b6001600160a01b031663c0fd8bde85856040518363ffffffff1660e01b8152600401613d05929190614ac6565b60006040518083038186803b158015613d1d57600080fd5b505afa158015613d31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d599190810190614706565b50909250905080613d7d57604051632acbe91560e01b815260040160405180910390fd5b50613d9081606001518260800151610b6d565b610a815760405163e60dce7160e01b815260040160405180910390fd5b6000806000613df185858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613f5c92505050565b600188019790915089013560f81c60005b8160ff16811015613e345760148901988b01356001600160601b031916613e298482613f8f565b935050600101613e02565b50506001600160601b03199081169516949094149794965093945050505050565b613e5d614061565b60208483018181013560c090811c600790810b900b6040858101919091526028830135821c6060860152603083013560e01c600390810b900b85850152603483013590911c84528051601f8701849004840281018401909152858152603c90940193903591600091613eeb918890889081908401838280828437600092019190915250889250613fdb915050565b868501600881013560c090811c600790810b900b6080870152601090910135901c60a0850152601890940193905084841115613f3a5760405163734fff6760e11b815260040160405180910390fd5b93509350939050565b60608315613f52575081610e2a565b610e2a8383613fe3565b6000610a81600083604051602001613f75929190614a10565b604051602081830303815290604052805160209091012090565b60006001600160601b03198083169084161115613faa579091905b604051600160f81b60208201526001600160601b0319808516602183015283166035820152610e2a90604901613f75565b016008015190565b815115613ff35781518083602001fd5b8060405162461bcd60e51b815260040161096a9190614af5565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160608101909152600081526020810161404f61400d565b815260200161405c61400d565b905290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201819052610100820183905261012082015261014081019190915290565b5080546000825560020290600052602060002090810190610b6a91905b8082111561412e57805461ffff191681556000600182015560020161410e565b5090565b80356001600160a01b038116811461414957600080fd5b919050565b60008083601f84011261415f578182fd5b5081356001600160401b03811115614175578182fd5b6020830191508360208260051b850101111561321457600080fd5b600082601f8301126141a0578081fd5b815160206001600160401b038211156141bb576141bb614fa0565b6141c9818360051b01614d75565b80838252828201915082860187848660071b89010111156141e8578586fd5b855b8581101561424b57608080838b031215614202578788fd5b61420a614d2a565b8351815286840151878201526040614223818601614326565b908201526060614234858201614326565b9082015285529385019391909101906001016141ea565b5090979650505050505050565b8051801515811461414957600080fd5b600082601f830112614278578081fd5b813561428b61428682614da5565b614d75565b81815284602083860101111561429f578283fd5b816020850160208301379081016020019190915292915050565b600082601f8301126142c9578081fd5b81516142d761428682614da5565b8181528460208386010111156142eb578283fd5b611b9a826020830160208701614f2d565b805161414981614fb6565b805163ffffffff8116811461414957600080fd5b805161414981614fc6565b805160ff8116811461414957600080fd5b600060208284031215614348578081fd5b610e2a82614132565b6000806000806000806000806000806101008b8d031215614370578586fd5b6143798b614132565b995060208b01356001600160401b0380821115614394578788fd5b6143a08e838f0161414e565b909b50995060408d01359150808211156143b8578788fd5b506143c58d828e0161414e565b90985096505060608b01356143d981614fb6565b945060808b0135935060a08b01356143f081614fc6565b8093505060c08b0135915060e08b013590509295989b9194979a5092959850565b60008060408385031215614423578182fd5b61442c83614132565b915060208301356001600160401b03811115614446578182fd5b61445285828601614268565b9150509250929050565b6000806020838503121561446e578182fd5b82356001600160401b03811115614483578283fd5b61448f8582860161414e565b90969095509350505050565b600080600080600080606087890312156144b3578384fd5b86356001600160401b03808211156144c9578586fd5b6144d58a838b0161414e565b909850965060208901359150808211156144ed578586fd5b6144f98a838b0161414e565b90965094506040890135915080821115614511578384fd5b5061451e89828a0161414e565b979a9699509497509295939492505050565b60008060008060008060808789031215614548578384fd5b86356001600160401b038082111561455e578586fd5b61456a8a838b0161414e565b90985096506020890135915080821115614582578586fd5b5061458f89828a0161414e565b90955093505060408701356145a381614fc6565b915060608701356145b381614fc6565b809150509295509295509295565b6000602082840312156145d2578081fd5b5035919050565b6000602082840312156145ea578081fd5b5051919050565b60008060408385031215614603578182fd5b50508035926020909101359150565b60008060208385031215614624578182fd5b82356001600160401b038082111561463a578384fd5b818501915085601f83011261464d578384fd5b81358181111561465b578485fd5b86602082850101111561466c578485fd5b60209290920196919550909350505050565b60006020828403121561468f578081fd5b81356001600160401b038111156146a4578182fd5b611b9a84828501614268565b6000604082840312156146c1578081fd5b604051604081018181106001600160401b03821117156146e3576146e3614fa0565b60405282356146f181614fb6565b81526020928301359281019290925250919050565b60008060006060848603121561471a578081fd5b83516001600160401b0380821115614730578283fd5b908501906101608288031215614744578283fd5b61474c614d52565b61475583614326565b815261476360208401614307565b602082015261477460408401614307565b6040820152614785606084016142fc565b6060820152608083015160808201526147a060a0840161431b565b60a08201526147b160c08401614326565b60c082015260e0830151828111156147c7578485fd5b6147d3898286016142b9565b60e0830152506101006147e7818501614307565b9082015261012083810151838111156147fe578586fd5b61480a8a828701614190565b91830191909152506101408381015190820152945061482b60208701614258565b93506040860151915080821115614840578283fd5b5061484d868287016142b9565b9150509250925092565b600060208284031215614868578081fd5b8135610e2a81614fb6565b600060208284031215614884578081fd5b8151610e2a81614fb6565b600080604083850312156148a1578182fd5b82356148ac81614fb6565b946020939093013593505050565b6000602082840312156148cb578081fd5b610e2a82614307565b6000602082840312156148e5578081fd5b8135610e2a81614fc6565b6000815180845260208085019450808401835b8381101561493757614924878351805161ffff168252602090810151910152565b6040969096019590820190600101614903565b509495945050505050565b6000815180845261495a816020860160208601614f2d565b601f01601f19169290920160200192915050565b8051825260208101516149b46020840182805160070b82526001600160401b036020820151166020830152604081015160030b6040830152606081015160608301525050565b50604081810151805160070b60a085015260208101516001600160401b031660c08501529081015160030b60e08401526060810151610100840152611fd0565b60008251614a06818460208701614f2d565b9190910192915050565b60ff60f81b8360f81b16815260008251614a31816001850160208701614f2d565b919091016001019392505050565b602081526000610e2a60208301846148f0565b604081526000614a6560408301856148f0565b828103602084015261324981856148f0565b6020808252825182820181905260009190848201906040850190845b81811015614aba57614aa683855161496e565b928401926101209290920191600101614a93565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b602081526000610e2a6020830184614942565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020815260008251602080840152611b9a6040840182614942565b815161ffff1681526020808301519082015260408101610a81565b602081526000825160048110614c3957614c39614f8a565b80602084015250602083015160078110614c5557614c55614f8a565b8060408401525061ffff60408401511660608301526060830151608080840152611b9a60a0840182614942565b6101208101610a81828461496e565b815160070b81526020808301516001600160401b03169082015260408083015160030b908201526060808301519082015260808101610a81565b6020815260008251602080840152611b9a60408401826148f0565b6000808335601e19843603018112614cfc578283fd5b8301803591506001600160401b03821115614d15578283fd5b60200191503681900382131561321457600080fd5b604051608081016001600160401b0381118282101715614d4c57614d4c614fa0565b60405290565b60405161016081016001600160401b0381118282101715614d4c57614d4c614fa0565b604051601f8201601f191681016001600160401b0381118282101715614d9d57614d9d614fa0565b604052919050565b60006001600160401b03821115614dbe57614dbe614fa0565b50601f01601f191660200190565b60008085851115614ddb578182fd5b83861115614de7578182fd5b5050820193919092039150565b60008219821115614e0757614e07614f74565b500190565b600181815b80851115614e47578160001904821115614e2d57614e2d614f74565b80851615614e3a57918102915b93841c9390800290614e11565b509250929050565b6000610e2a8383600082614e6557506001610a81565b81614e7257506000610a81565b8160018114614e885760028114614e9257614eae565b6001915050610a81565b60ff841115614ea357614ea3614f74565b50506001821b610a81565b5060208310610133831016604e8410600b8410161715614ed1575081810a610a81565b614edb8383614e0c565b8060001904821115614eef57614eef614f74565b029392505050565b6000816000190483118215151615614f1157614f11614f74565b500290565b600082821015614f2857614f28614f74565b500390565b60005b83811015614f48578181015183820152602001614f30565b838111156118305750506000910152565b6000600019821415614f6d57614f6d614f74565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff81168114610b6a57600080fd5b6001600160401b0381168114610b6a57600080fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122063879d46e9f3904806f40ff728d3db0ce591c638b906b6667934e69e863213f164736f6c63430008040033",
  "id": 7
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":7,"method":"eth_getCode","params":["0xa2aa501b19aff244d90cc15a4cf739d2725b5729","0x3f8473"]}'
```

---

## eth_getLogs - Etherlink RPC Method

# eth_getLogs - Etherlink RPC Method

Returns an array of all logs matching a given filter object on Etherlink.

## When to Use This Method

Read one Pyth event using its contract address, both captured topics, and exact block 4,162,675. This is not a Transfer event.

## Block-range limits

The verified request queries one historical block. These probes do not establish the maximum supported range.

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Request Parameters

- `filter` (`Object, required`): Filter with fromBlock, toBlock, address, and topics. Keep the recorded values together.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "eth_getLogs",
  "params": [
    {
      "fromBlock": "0x3f8473",
      "toBlock": "0x3f8473",
      "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
      "topics": [
        "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
        "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
      ]
    }
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    {
      "address": "0x2880ab155794e7179c9ee2e38200202908c17b43",
      "topics": [
        "0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec",
        "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000672c90e9000000000000000000000000000000000000000000000000000006ce3a4ea33600000000000000000000000000000000000000000000000000000000b7e490b1",
      "blockNumber": "0x3f8473",
      "transactionHash": "0xb693a7ef2ccb8893f990d8ec912070ddd2466755e1be8bee558db2ae5920bd66",
      "transactionIndex": "0x0",
      "blockHash": "0x553b9c9688501f47ce83084a18120cbacef819f98d7681ad0cbbb4812a90fae9",
      "logIndex": "0x0",
      "removed": false
    }
  ],
  "id": 5
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":5,"method":"eth_getLogs","params":[{"fromBlock":"0x3f8473","toBlock":"0x3f8473","address":"0x2880ab155794e7179c9ee2e38200202908c17b43","topics":["0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec","0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"]}]}'
```

---

## eth_getStorageAt - Etherlink RPC Method

# eth_getStorageAt - Etherlink RPC Method

Returns the value from a storage position at a given address on Etherlink. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

## When to Use This Method

Read the Pyth proxy implementation slot at block 4,162,675. The request uses the ERC-1967 implementation slot.

## Request Parameters

- `address` (`DATA, required`): 20-byte account or contract address.
- `position` (`QUANTITY, required`): Storage slot. The example uses the ERC1967 implementation slot.
- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "eth_getStorageAt",
  "params": [
    "0x2880ab155794e7179c9ee2e38200202908c17b43",
    "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
    "0x3f8473"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0x000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b5729",
  "id": 6
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":6,"method":"eth_getStorageAt","params":["0x2880ab155794e7179c9ee2e38200202908c17b43","0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc","0x3f8473"]}'
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

---

## eth_getTransactionByHash - Etherlink RPC Method

# eth_getTransactionByHash - Etherlink RPC Method

Returns the information about a transaction by transaction hash on Etherlink.

## When to Use This Method

Read the transaction recorded in block 4,162,737 using its hash.

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "eth_getTransactionByHash",
  "params": [
    "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": {
    "blockHash": "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
    "blockNumber": "0x3f84b1",
    "from": "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
    "gas": "0x4c4b40",
    "gasPrice": "0x3b9aca00",
    "hash": "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",
    "input": "0xc14c9204000000000000000000000000000000000000000000000000000001930619e2a045544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000109c886e2a7ed5cf552ceb4d68ffb852fc04e0a01055016552a1810caffa1ee52702b8cccd149c9d6a61ad37b759e3f4be464d8cdd01f52c29055d88485e489fe1b45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176c0e69c01930619e2a00000002000000151bfef864077e299879f09ddde98a3bd5e18b0f76038ef2f159fa841e2dbe093317ed9bfb4134f6a064de1c7f66e1f0dd64d13233d3b1907958583168a8ba4631b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce630dfee501930619e2a0000000200000016a56b8ce99eedd20dd230dc9cea28ccb27a83455c5a058750150db945dd08f532e8e0495bf5f2b0f5f72c2f2d898391852363a219b41f964964050720149461e1b4254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ce62febb8d01930619e2a0000000200000010a78ef21ed2dbb7d94f8cbf46be9e4413ad64dc39482d0b9aec50ea48fa64123583775a5f9e065ccfe8867ee34314f0c7d2dfa79c3688d68658be2ea7e567d531c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a0000000200000013f08d6d551abc925e12f0e394776bf39f6b525cf7da28a2e14389c55ed8e323127743b2c86b02c2860174c2c8182675c40327813d67ee846a0886919ac3e89c31c58545a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003db82ea01930619e2a000000020000001dbecf87431878794f047b813cdada29af88541ce656caa4d95008910970eed91431189604d3f9c4fb3a9bc629bf882171dd1be4e058ca9ea07e43036954bfeb11b00063137333039373432303132303623302e352e3123646174612d7061636b616765732d77726170706572000029000002ed57011e0000",
    "nonce": "0x1123fd",
    "to": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
    "transactionIndex": "0x0",
    "value": "0x0",
    "v": "0x14e76",
    "r": "0x98d3b2e5cff6d0a0facc6a13a2df8626aaccf1573d29e7b1d18521ba470d3a08",
    "s": "0x854b2712ea3568c5da1d7ab51d45c906e5f7f32b671bf69d56a03b2a1c7c9d9"
  },
  "id": 2
}
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":2,"method":"eth_getTransactionByHash","params":["0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587"]}'
```

---

## eth_getTransactionCount - Etherlink RPC Method

# eth_getTransactionCount - Etherlink RPC Method

Returns the number of transactions sent from an address on Etherlink, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

## When to Use This Method

Read the demonstrated account transaction count at block 1,000,000.

## Request Parameters

- `address` (`DATA, required`): 20-byte account or contract address.
- `blockNumber` (`QUANTITY, required`): Block number in hexadecimal. The example uses the recorded historical height.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 20,
  "method": "eth_getTransactionCount",
  "params": [
    "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
    "0xf4240"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "0x4a2b1",
  "id": 20
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":20,"method":"eth_getTransactionCount","params":["0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b","0xf4240"]}'
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

---

## eth_getTransactionReceipt - Etherlink RPC Method

# eth_getTransactionReceipt - Etherlink RPC Method

Returns the receipt of a transaction by transaction hash on Etherlink. Receipt is only available for mined transactions.

## When to Use This Method

Read the execution receipt for the recorded transaction in block 4,162,737.

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 24,
  "method": "eth_getTransactionReceipt",
  "params": [
    "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587"
  ]
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": {
    "transactionHash": "0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587",
    "transactionIndex": "0x0",
    "blockHash": "0x8fccc43a1a50e7888b945a82c2c239908ead9ee4720c30774e9f58a2c40a3ad1",
    "blockNumber": "0x3f84b1",
    "from": "0x5d66ec78664f4a0b0929a41270316a6cd4d8bd4b",
    "to": "0xa2cca359c43839040cf3d230deb1689ab8db2dac",
    "cumulativeGasUsed": "0x4564ea",
    "effectiveGasPrice": "0x3b9aca00",
    "gasUsed": "0x4564ea",
    "logs": [],
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "type": "0x0",
    "status": "0x1",
    "contractAddress": null
  },
  "id": 24
}
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":24,"method":"eth_getTransactionReceipt","params":["0x0dc908c545bfefe9fd5b5198e39c1af2b3166e5e556a51f2efd55c4a449fa587"]}'
```

---

## web3_clientVersion - Etherlink RPC Method

# web3_clientVersion - Etherlink RPC Method

Returns the current client software version string for your Etherlink node, including the client name, version number, OS, and runtime.

## When to Use This Method

Read the running client version. The captured value identifies Octez EVM node 0.66.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "web3_clientVersion",
  "params": []
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": "octez-evm-node/octez-evm-node 0.66 (build: 0)-9cfabac8/Unix/ocamlc.5.3.0",
  "id": 1
}
```

## Code Examples

```bash
curl -X POST "https://api-etherlink-mainnet.n.dwellir.com/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data-raw '{"jsonrpc":"2.0","id":1,"method":"web3_clientVersion","params":[]}'
```

## Best Practices

Keep the recorded block height and address together when reproducing a historical example. Preserve RPC errors instead of replacing them with empty results.

---

## Flow EVM RPC with Dwellir

# Flow EVM RPC with Dwellir

## Flow EVM RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Flow EVM supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Flow EVM?

Flow EVM brings Ethereum compatibility to the Flow ecosystem so you can reuse your Solidity code, tools, and workflows with minimal changes.

- EVM JSON-RPC compatible: works with ethers, viem, web3.js, and web3.py
- Common frameworks: Hardhat, Foundry, and Truffle supported
- Familiar UX: MetaMask and other EVM wallets connect seamlessly
- Dwellir infra: global anycast, Archive/Trace/Debug/WebSocket support, and 99.99% uptime SLA

## Quick Start with Flow EVM

Connect to Flow EVM in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Flow EVM mainnet
const provider = new JsonRpcProvider(
  'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Flow EVM mainnet
const web3 = new Web3(
  'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Flow EVM:', chainId === 747);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';

// Create Flow EVM client
const client = createPublicClient({
  transport: http('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to Flow EVM mainnet
web3 = Web3(Web3.HTTPProvider(
  'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection
print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)

# Get latest block
latest_block = web3.eth.get_block('latest')
print(f'Latest block: {latest_block.number}')
```

## Network Information

| Parameter        | Value                 | Details          |
| ---------------- | --------------------- | ---------------- |
| Mainnet Chain ID | 747 (0x2eb)           | Flow EVM Mainnet |
| Testnet Chain ID | 545 (0x221)           | Flow EVM Testnet |
| RPC Standard     | Ethereum JSON-RPC 2.0 | EVM-compatible   |

## API Reference

Flow EVM supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/).

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash, confirmations = 1) {
  return provider.waitForTransaction(txHash, confirmations);
}
```

### Gas Optimization

Optimize gas costs on Flow EVM:

```javascript
// Get current fee data (EIP-1559)
const feeData = await provider.getFeeData();

// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Calculate total cost (approx.)
const totalCost = gasEstimate * (feeData.gasPrice ?? 0n);
console.log('Estimated cost:', totalCost);
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
import { JsonRpcProvider } from 'ethers';

class FlowProvider {
  static instance = null;
  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Transaction underpriced"

Flow EVM uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from Ethereum to Flow EVM requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Flow EVM)
const provider = new JsonRpcProvider(
  'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (747)
// Note: Separate block numbers
```

## Resources & Tools

### Need Help?

- **Email**: <support@dwellir.com>
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Get Access**: [Get your API key](https://dashboard.dwellir.com/register)

---

## debug_traceBlock - Flow EVM RPC Method

# debug_traceBlock - Flow EVM RPC Method

Traces all transactions in a block on Flow EVM Gateway by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Flow EVM Gateway - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Flow EVM
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Flow EVM:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Flow EVM blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Flow EVM RPC Method

# debug_traceBlockByHash - Flow EVM RPC Method

Traces all transactions in a block on Flow EVM Gateway identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Flow EVM Gateway - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Flow EVM
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Flow EVM:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Flow EVM:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Flow EVM RPC Method

# debug_traceBlockByNumber - Flow EVM RPC Method

Traces all transactions in a block on Flow EVM Gateway identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Flow EVM Gateway - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Flow EVM execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Flow EVM:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Flow EVM:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Flow EVM RPC Method

# debug_traceCall - Flow EVM RPC Method

Traces a call on Flow EVM Gateway without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Flow EVM Gateway - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Flow EVM
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "data": "0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
        "data": "0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
        "data": "0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    data: '0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    data: '0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    'data': '0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
        "data": "0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Flow EVM to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Flow EVM:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Flow EVM:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/flow-evm-gateway/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Flow EVM RPC Method

# debug_traceTransaction - Flow EVM RPC Method

Traces a transaction execution on Flow EVM Gateway by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Flow EVM
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Flow EVM RPC Method

# eth_accounts - Flow EVM RPC Method

Returns a list of addresses owned by the client on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Flow EVM RPC Method

# eth_blockNumber - Flow EVM RPC Method

Returns the number of the most recent block on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_blockNumber` is fundamental for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Syncing Applications** - Keep your dApp in sync with the latest Flow EVM blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Flow EVM block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Flow EVM block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Flow EVM block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Flow EVM block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Flow EVM block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Flow EVM:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Flow EVM:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Flow EVM node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/flow-evm-gateway/eth_syncing) - Check if node is still syncing

---

## eth_call - Flow EVM RPC Method

# eth_call - Flow EVM RPC Method

Executes a new message call immediately without creating a transaction on Flow EVM Gateway. Used for reading smart contract state.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

The `eth_call` method serves these key scenarios for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Flow EVM
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';
const walletAddress = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Flow EVM. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Flow EVM
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Flow EVM Gateway

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "data": "0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "data": "0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    data := common.FromHex("0x70a08231000000000000000000000000d3bF53DAC106A0290B0483EcBC89d40FcC961f3e")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Flow EVM RPC Method

# eth_chainId - Flow EVM RPC Method

Returns the chain ID used for transaction signing on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_chainId` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/flow-evm-gateway/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/flow-evm-gateway/eth_syncing) - Check sync status

---

## eth_coinbase - Flow EVM RPC Method

# eth_coinbase - Flow EVM RPC Method

Checks the legacy `eth_coinbase` compatibility method on Flow EVM Gateway. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Flow EVM coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Flow EVM coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Flow EVM coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Flow EVM coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Flow EVM coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Flow EVM nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/flow-evm-gateway/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/flow-evm-gateway/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/flow-evm-gateway/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Flow EVM RPC Method

# eth_estimateGas - Flow EVM RPC Method

Estimates the gas necessary to execute a transaction on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Flow EVM
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Flow EVM.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Flow EVM may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "to": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/flow-evm-gateway/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Flow EVM RPC Method

# eth_feeHistory - Flow EVM RPC Method

Returns historical gas fee data on Flow EVM Gateway, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Flow EVM without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Flow EVM.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Flow EVM) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/flow-evm-gateway/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Flow EVM RPC Method

# eth_gasPrice - Flow EVM RPC Method

Returns the current gas price on Flow EVM Gateway in wei.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Flow EVM
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Flow EVM. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Flow EVM, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Flow EVM: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Flow EVM supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/flow-evm-gateway/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Flow EVM RPC Method

# eth_getBalance - Flow EVM RPC Method

Returns the balance of a given address on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getBalance` is fundamental for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Flow EVM
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Flow EVM Gateway
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Flow EVM Gateway. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Flow EVM`);
  return balance;
}

displayBalance('0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Flow EVM at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Flow EVM')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Flow EVM')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Flow EVM Gateway.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Flow EVM RPC Method

# eth_getBlockByHash - Flow EVM RPC Method

Returns information about a block by hash on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getBlockByHash` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Flow EVM Gateway
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Flow EVM Gateway.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Flow EVM Gateway.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Flow EVM RPC Method

# eth_getBlockByNumber - Flow EVM RPC Method

Returns information about a block by block number on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getBlockByNumber` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Flow EVM Gateway
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Flow EVM Gateway with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Flow EVM Gateway. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Flow EVM RPC Method

# eth_getBlockReceipts - Flow EVM RPC Method

Returns all transaction receipts for a block on Flow EVM Gateway. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getBlockReceipts` is useful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Flow EVM Gateway, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Flow EVM Gateway. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xee0158dc7a2e89b3de711f135d5d39f2bf5fa407233501c4b58a065bfe7089b8",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Flow EVM RPC Method

# eth_getCode - Flow EVM RPC Method

Returns the bytecode at a given address on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getCode` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Flow EVM
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Flow EVM:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Flow EVM:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Flow EVM RPC Method

# eth_getFilterChanges - Flow EVM RPC Method

Polls a filter on Flow EVM Gateway for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getFilterChanges` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Flow EVM
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Flow EVM:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Flow EVM RPC Method

# eth_getFilterLogs - Flow EVM RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Flow EVM Gateway. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getFilterLogs` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Flow EVM
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Flow EVM RPC Method

# eth_getLogs - Flow EVM RPC Method

Returns an array of all logs matching a given filter object on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Flow EVM for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Flow EVM Gateway
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Flow EVM.

```javascript
const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Flow EVM enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Flow EVM Gateway, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Flow EVM RPC Method

# eth_getStorageAt - Flow EVM RPC Method

Returns the value from a storage position at a given address on Flow EVM Gateway. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getStorageAt` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **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 consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **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": [
    "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "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-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', '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-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';

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-flow-evm-gateway-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 = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
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-flow-evm-gateway-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-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    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 Flow EVM:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-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-flow-evm-gateway-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 = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';
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 Flow EVM:`);
  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/flow-evm-gateway/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Flow EVM RPC Method

# eth_getTransactionByHash - Flow EVM RPC Method

Returns the information about a transaction by transaction hash on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getTransactionByHash` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Flow EVM Gateway
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Flow EVM Gateway. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Flow EVM Gateway. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Flow EVM RPC Method

# eth_getTransactionCount - Flow EVM RPC Method

Returns the number of transactions sent from an address on Flow EVM Gateway, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getTransactionCount` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Flow EVM
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Flow EVM nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e'
nonce = get_transaction_count(address)
print(f'Flow EVM nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Flow EVM nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Flow EVM:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Flow EVM RPC Method

# eth_getTransactionReceipt - Flow EVM RPC Method

Returns the receipt of a transaction by transaction hash on Flow EVM Gateway. Receipt is only available for mined transactions.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_getTransactionReceipt` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Flow EVM Gateway and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Flow EVM Gateway. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Flow EVM Gateway, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xac905cb8672fe39508dab7199529d77b32d459242ad9d3f6799e4e427d6003f8")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Flow EVM RPC Method

# eth_hashrate - Flow EVM RPC Method

Returns the legacy `eth_hashrate` compatibility value on Flow EVM Gateway. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Flow EVM hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Flow EVM hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Flow EVM hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Flow EVM hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Flow EVM hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/flow-evm-gateway/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/flow-evm-gateway/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Flow EVM RPC Method

# eth_maxPriorityFeePerGas - Flow EVM RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Flow EVM Gateway. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Flow EVM
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Flow EVM priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Flow EVM priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Flow EVM priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Flow EVM:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Flow EVM:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/flow-evm-gateway/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/flow-evm-gateway/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Flow EVM RPC Method

# eth_mining - Flow EVM RPC Method

Checks the legacy `eth_mining` compatibility method on Flow EVM Gateway. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Flow EVM mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Flow EVM mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Flow EVM mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Flow EVM mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Flow EVM mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/flow-evm-gateway/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/flow-evm-gateway/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Flow EVM RPC Method

# eth_newBlockFilter - Flow EVM RPC Method

Creates a filter on Flow EVM Gateway that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_newBlockFilter` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Block Monitoring** - Detect new blocks on Flow EVM as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Flow EVM:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Flow EVM RPC Method

# eth_newFilter - Flow EVM RPC Method

Creates a filter object on Flow EVM Gateway based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_newFilter` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Event Monitoring** - Subscribe to specific contract events on Flow EVM such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Flow EVM:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Flow EVM RPC Method

# eth_newPendingTransactionFilter - Flow EVM RPC Method

Creates a filter on Flow EVM Gateway that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Mempool Monitoring** - Observe unconfirmed transactions on Flow EVM to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Flow EVM...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Flow EVM:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Flow EVM RPC Method

# eth_protocolVersion - Flow EVM RPC Method

Returns the current Ethereum protocol version used by the Flow EVM Gateway node.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_protocolVersion` is useful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Flow EVM protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Flow EVM protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Flow EVM protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Flow EVM protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Flow EVM protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Flow EVM nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/flow-evm-gateway/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/flow-evm-gateway/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/flow-evm-gateway/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Flow EVM RPC Method

# eth_sendRawTransaction - Flow EVM RPC Method

Submits a pre-signed transaction for broadcast to Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Flow EVM
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Flow EVM mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/flow-evm-gateway/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/flow-evm-gateway/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Flow EVM RPC Method

# eth_sendTransaction - Flow EVM RPC Method

Creates and sends a new transaction from an unlocked account on Flow EVM Gateway. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Flow EVM tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Flow EVM tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Flow EVM tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Flow EVM tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Flow EVM tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Flow EVM dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/flow-evm-gateway/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Flow EVM RPC Method

# eth_signTransaction - Flow EVM RPC Method

Signs a transaction with the private key of the specified account on Flow EVM Gateway without submitting it to the network.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Flow EVM tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Flow EVM tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Flow EVM tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Flow EVM:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/flow-evm-gateway/eth_accounts) - List accounts available for signing

---

## eth_syncing - Flow EVM RPC Method

# eth_syncing - Flow EVM RPC Method

Returns the sync status of your Flow EVM Gateway node - either `false` when fully synced, or an object describing the sync progress.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_syncing` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Flow EVM node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Flow EVM node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Flow EVM node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/flow-evm-gateway/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/flow-evm-gateway/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/flow-evm-gateway/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Flow EVM RPC Method

# eth_uninstallFilter - Flow EVM RPC Method

Removes a filter on Flow EVM Gateway that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`eth_uninstallFilter` is important for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/flow-evm-gateway/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Flow EVM RPC Method

# net_listening - Flow EVM RPC Method

Checks whether the connected Flow EVM Gateway client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`net_listening` is useful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Flow EVM node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Flow EVM node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Flow EVM node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/flow-evm-gateway/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/flow-evm-gateway/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/flow-evm-gateway/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/flow-evm-gateway/web3_clientVersion) - Get node client info

---

## net_peerCount - Flow EVM RPC Method

# net_peerCount - Flow EVM RPC Method

Returns the number of peers currently connected to your Flow EVM Gateway node.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`net_peerCount` is important for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Flow EVM deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Flow EVM peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Flow EVM peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Flow EVM peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Flow EVM nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/flow-evm-gateway/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/flow-evm-gateway/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/flow-evm-gateway/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/flow-evm-gateway/web3_clientVersion) - Get node client info

---

## net_version - Flow EVM RPC Method

# net_version - Flow EVM RPC Method

Returns the current network ID on Flow EVM Gateway as a decimal string. The network ID identifies which network the node is connected to.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`net_version` is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Endpoint Identification** - Confirm your application is connected to the expected Flow EVM network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Flow EVM network ID:', networkId);

// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Flow EVM network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Flow EVM network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/flow-evm-gateway/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/flow-evm-gateway/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/flow-evm-gateway/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/flow-evm-gateway/eth_syncing) - Check node sync progress

---

## rpc_modules - Flow EVM RPC Method

# rpc_modules - Flow EVM RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Flow EVM Gateway endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`rpc_modules` is useful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/flow-evm-gateway/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Flow EVM RPC Method

# txpool_content - Flow EVM RPC Method

Returns the full pending and queued transaction pool for the connected Flow EVM Gateway endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`txpool_content` is useful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/flow-evm-gateway/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/flow-evm-gateway/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Flow EVM RPC Method

# txpool_status - Flow EVM RPC Method

Returns transaction pool counters for the connected Flow EVM Gateway endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`txpool_status` is valuable for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/flow-evm-gateway/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/flow-evm-gateway/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/flow-evm-gateway/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Flow EVM RPC Method

# web3_clientVersion - Flow EVM RPC Method

Returns the current client software version string for your Flow EVM Gateway node, including the client name, version number, OS, and runtime.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

## When to Use This Method

`web3_clientVersion` is valuable for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Flow EVM client:', clientVersion);

// Using fetch
const response = await fetch('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Flow EVM client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Flow EVM client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/flow-evm-gateway/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/flow-evm-gateway/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/flow-evm-gateway/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/flow-evm-gateway/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Flow EVM RPC Method

# web3_sha3 - Flow EVM RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Flow EVM Gateway.

> **Why Flow EVM?** Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-flow-evm-gateway-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/flow-evm-gateway/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/flow-evm-gateway/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/flow-evm-gateway/web3_clientVersion) - Get node client version

---

## Getting Started

# Getting Started

This guide helps you create an API key and make your first request in minutes.

For access errors, limits, historical queries, filters, regions, and account controls, see [RPC troubleshooting](https://www.dwellir.com/docs/getting-started/troubleshooting).

## 1. Sign Up and Get Your API Key

1. Go to [dashboard.dwellir.com](https://dashboard.dwellir.com) and sign up
2. Your first API key is created automatically -- find it in the API Keys section
3. Copy your API key (format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)

Need additional keys? Create them from the dashboard or the [Dwellir CLI](https://www.dwellir.com/docs/cli):

```bash
curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh
dwellir auth login
dwellir keys create --name my-key
dwellir keys copy my-key
```

The CLI shows keys masked. `dwellir keys copy` copies the full key to your clipboard. `dwellir keys env` writes it to `.env`.

## 2. Choose a Network

Select from 150+ supported networks. Popular choices include:

- **Ethereum**: `ethereum-mainnet`
- **Base**: `base-mainnet`
- **Arbitrum**: `arbitrum-one`
- **Polygon**: `polygon-mainnet`
- **Polkadot**: `polkadot`

See the full list in [Supported Chains](https://www.dwellir.com/docs/getting-started/supported-chains), or use the CLI to browse all endpoints:

```bash
dwellir endpoints search ethereum
dwellir endpoints list --ecosystem evm --network mainnet
```

## 3. Make Your First Request

Dwellir accepts your API key in the endpoint URL or the `X-Api-Key` header. Both approaches use the same key, quotas, and usage accounting.

### API key in the URL

Put the key after the endpoint host. This approach works with clients that cannot set custom headers.

```bash
curl -X POST \
  -H "Content-Type: application/json" \
  https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

### API key in the header

Send `X-Api-Key` when you need to keep the key out of URLs recorded by logs or traces.

```bash
curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: YOUR_API_KEY" \
  https://api-ethereum-mainnet.n.dwellir.com \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Endpoint URL Format

```
https://api-{network}.n.dwellir.com/{YOUR_API_KEY}
wss://api-{network}.n.dwellir.com/{YOUR_API_KEY}
```

See [API authentication](https://www.dwellir.com/docs/getting-started/authentication) for HTTP, WebSocket, and gRPC examples. The guide also covers credential redaction.

## 4. Use an SDK

### Web3.js

```javascript
const Web3 = require('web3');

// This client example uses URL path authentication.
const web3 = new Web3('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

// Make requests
const blockNumber = await web3.eth.getBlockNumber();
console.log('Latest block:', blockNumber);

// Get balance
const balance = await web3.eth.getBalance('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'ETH');
```

### Ethers.js

```javascript
import { JsonRpcProvider } from 'ethers';

// This client example uses URL path authentication.
const provider = new JsonRpcProvider(
  'https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Make requests
const blockNumber = await provider.getBlockNumber();
console.log('Latest block:', blockNumber);

// Get balance
const balance = await provider.getBalance('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
console.log('Balance:', ethers.formatEther(balance), 'ETH');
```

### WebSocket Connection

```javascript
const WebSocket = require('ws');

const ws = new WebSocket('wss://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY');

ws.on('open', () => {
  // Subscribe to new blocks
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_subscribe',
    params: ['newHeads'],
    id: 1
  }));
});

ws.on('message', (data) => {
  const response = JSON.parse(data);
  console.log('New block:', response);
});
```

## 5. Configure API Quotas

Protect yourself from unexpected usage by setting quotas on your API keys:

1. Go to [dashboard.dwellir.com/api-keys](https://dashboard.dwellir.com/api-keys)
2. Click the edit icon next to your API key
3. In the Edit API key dialog:
   - **Name**: Give your key a descriptive name
   - **Daily quota**: Toggle and set daily request limit
   - **Monthly quota**: Toggle and set monthly request limit
4. Click "Update API Key" to save changes

Or set quotas from the CLI:

```bash
dwellir keys create --name production --daily-quota 100000 --monthly-quota 3000000
```

When a quota is reached, the API returns a 429 error until the quota resets.

## 6. Restrict the Key by Source IP

An API key works from any network until you restrict it. Create an IP whitelist so only known source IPs can use the key.

Open the [IP Whitelisting tab](https://dashboard.dwellir.com/api-keys?tab=ip-whitelisting). Follow [API key IP whitelisting](https://www.dwellir.com/docs/getting-started/ip-whitelisting) for the dashboard steps. See [When to use IP whitelisting](https://www.dwellir.com/guides/when-to-use-ip-whitelisting) before you enable it on a live key.

## 7. Monitor Your Usage

Track your API usage in real-time:

1. Go to [dashboard.dwellir.com/usage](https://dashboard.dwellir.com/usage)
2. View metrics: total requests, requests by method/network, response times, and error rates

Or use the CLI for programmatic access:

```bash
dwellir usage summary
dwellir usage history --interval day
dwellir logs errors --status-code 429
```

## 8. Best Practices

### Error Handling

```javascript
async function makeRequest() {
  try {
    const blockNumber = await web3.eth.getBlockNumber();
    return blockNumber;
  } catch (error) {
    if (error.code === 429) {
      console.log('Rate limit exceeded, retry after delay');
      // Implement exponential backoff
    } else {
      console.error('Request failed:', error);
    }
  }
}
```

### Connection Pooling

```javascript
// Reuse provider instances
const providers = {
  ethereum: new Web3('https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY'),
  polygon: new Web3('https://api-polygon-mainnet.n.dwellir.com/YOUR_API_KEY'),
  arbitrum: new Web3('https://api-arbitrum-one.n.dwellir.com/YOUR_API_KEY')
};

// Use the same provider for multiple requests
async function getMultiChainData() {
  const ethBlock = await providers.ethereum.eth.getBlockNumber();
  const polyBlock = await providers.polygon.eth.getBlockNumber();
  const arbBlock = await providers.arbitrum.eth.getBlockNumber();

  return { ethBlock, polyBlock, arbBlock };
}
```

### Batch Requests

```javascript
// Batch multiple calls into one request
const batch = new web3.BatchRequest();

batch.add(web3.eth.getBlockNumber.request((err, res) => {
  console.log('Block number:', res);
}));

batch.add(web3.eth.getGasPrice.request((err, res) => {
  console.log('Gas price:', res);
}));

batch.execute();
```

## Migrating from Another Provider

Switching from Alchemy, Infura, QuickNode, or another RPC provider? Use the migration prompt below with your AI coding agent to automate the process. It scans your codebase for existing RPC endpoints, matches them against Dwellir's catalog, and replaces the URLs.

View and copy the migration prompt

```text
Migrate this project's blockchain RPC endpoints to Dwellir. Follow the phases below in order. Use subagents and background processes to parallelize work wherever your tooling supports it.

## Phase 1 — Environment & Endpoint Discovery

1. Check whether the Dwellir CLI is installed by running `dwellir --version`. If the command is not found, suggest the user install it:
   curl -fsSL https://raw.githubusercontent.com/dwellir-public/cli/main/scripts/install.sh | sh
2. Obtain the full list of Dwellir-supported chains, networks, and node types (full vs archive). Try one of these approaches in order until one succeeds:
   a. **CLI** (preferred): Run `dwellir endpoints list` to get the complete endpoint catalog.
   b. **Documentation**: If the CLI is unavailable or the user declines to install it, fetch https://www.dwellir.com/docs.md or https://www.dwellir.com/networks.md for the supported endpoint list.
   c. **Dashboard export**: As a last resort, ask the user to go to dashboard.dwellir.com/endpoints and press the Export button (top-left) to export all endpoints as CSV, Markdown, or JSON, then share the file with you.
3. Check whether the project uses separate configurations per environment (production, staging, development, etc.). If it does, ask the user to provide a Dwellir API key for each environment. If there is only one environment, ask for a single key.

## Phase 2 — Codebase Discovery

Scan the entire codebase in parallel where possible:

1. Find every RPC endpoint URL (look for domains like infura.io, alchemy.com, quicknode.com, chainstack.com, ankr.com, blast.io, drpc.org, and any other known RPC providers, as well as raw IP/port patterns and chain-specific gateway URLs).
2. Identify each endpoint's chain, network, and authentication method (API key in URL path, header, query param, or none).
3. Determine whether the code requires an archive node or a full node for each endpoint (look for calls to historical state such as eth_getBalance at old block heights, debug_*/trace_* namespaces, or large block-range log filters).
4. Check if the codebase interacts with Hyperliquid. If it does, suggest that the user install Dwellir's Hyperliquid Skills: npx skills add https://github.com/dwellir-public/hyperliquid-skills

## Phase 3 — Compatibility Matching

For each discovered endpoint:

1. Compare the chain + network against the Dwellir endpoints list from Phase 1. Note that some providers (especially for EVM chains) use chain ID-based naming in their URLs rather than chain + network names — resolve any ambiguity by calling the endpoint's RPC method for chain ID (e.g., eth_chainId) and comparing the result against the chain ID returned by the corresponding Dwellir endpoint to confirm they serve the same network.
2. If the code requires an archive node and Dwellir only offers a full node for that chain, mark the endpoint as unsupported and do NOT migrate it.
3. For EVM chains, check whether the codebase depends on client-specific response shapes (e.g., Geth/Erigon trace formats vs Reth, differences in debug_traceTransaction output, or Parity-style trace_* responses). Use web search if needed to understand current client-level differences. Flag any potential incompatibilities.

## Phase 4 — Migration

1. Create a new branch (e.g., chore/migrate-to-dwellir) — NEVER commit directly to main.
2. For each supported endpoint, replace the provider URL with the equivalent Dwellir endpoint URL and update the authentication to use the correct Dwellir API key for each environment. Preserve the existing configuration pattern (env var, config file, etc.).
3. If any endpoints, chains, or networks in the codebase are NOT supported by Dwellir, do not touch them.

## Phase 5 — Summary

Present a clear summary with:

- Migrated: list of endpoints successfully switched to Dwellir (chain, network, full/archive).
- Flagged: any EVM client compatibility concerns the user should verify.
- Not supported: list of endpoints/chains/networks Dwellir does not currently support, along with whether each requires a full or archive node and the estimated monthly request volume if determinable from the code. Ask the user to reach out to support@dwellir.com or the team on https://t.me/dwellir with this list so Dwellir can evaluate adding support.

If there are any questions about supported RPC methods or Dwellir services, consult https://www.dwellir.com/docs/llms.txt and https://www.dwellir.com/docs.md for authoritative reference.

Commit the changes and ask the user whether you should push the branch to origin and open a pull request.
```

See [Agent Tooling](https://www.dwellir.com/docs/agents) for more tools and documentation endpoints built for AI coding agents.

## Quick Reference

### Endpoint Format

```
https://api-{network}.n.dwellir.com/{YOUR_API_KEY}
wss://api-{network}.n.dwellir.com/{YOUR_API_KEY}
```

### Common Networks

- Ethereum: `api-ethereum-mainnet`
- Base: `api-base-mainnet`
- Arbitrum: `api-arbitrum-one`
- Optimism: `api-optimism-mainnet`
- Polygon: `api-polygon-mainnet`
- BSC: `api-bsc-mainnet`
- Avalanche: `api-avalanche-c-chain`

### Useful Links

- [Dashboard](https://dashboard.dwellir.com)
- [API Keys](https://dashboard.dwellir.com/api-keys)
- [Usage Monitor](https://dashboard.dwellir.com/usage)
- [Dwellir CLI](https://www.dwellir.com/docs/cli)
- [Supported Chains](https://www.dwellir.com/docs/getting-started/supported-chains)
- [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits)
- [Shared Node Pricing](https://www.dwellir.com/docs/getting-started/pricing)
- [Unlimited Node Pricing](https://www.dwellir.com/docs/getting-started/unlimited-node-pricing)

## Need Help?

- Check the [documentation](https://www.dwellir.com/docs/getting-started/supported-chains) for network-specific details
- Contact <support@dwellir.com> for technical assistance

Ready to scale? [Upgrade your plan](https://www.dwellir.com/docs/getting-started/pricing) for higher rate limits and additional features.

---

## Archive Nodes

# Archive Nodes

Archive nodes retain historical chain state for queries at past blocks. Use them for old balances, historical contract state, and supported tracing workflows.

Available history and methods depend on the chain, node client, and endpoint. Archive access alone does not guarantee genesis coverage, historical proofs, or every tracing method.

## Archive vs Full Nodes

| Node Type | What you get                                                                                          | Best for                                                                 |
| --------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| Archive   | Historical chain state and contract storage, plus debug/trace access where supported                  | Analytics, audits, historical balances, backfills, simulation, debugging |
| Full      | Recent chain state, latest blocks, current balances, transaction submission, and standard RPC queries | Wallets, dApps, trading bots, indexers focused on recent data            |

## When You Need an Archive Node

Use an archive endpoint when your workload depends on historical state, including:

- `eth_call` or `eth_getBalance` at old block heights
- `debug_*` and `trace_*` namespaces
- large historical log scans and replay workloads
- backfilling analytics across long block ranges
- reproducing or debugging past transaction behavior

If you only need current balances, recent blocks, transaction sending, or real-time subscriptions, a full node is usually enough.

## What Archive Nodes Store

Archive nodes retain:

- all historical blocks
- all historical transactions
- historical account balances and storage state
- contract state snapshots across past block heights

That extra history is why archive infrastructure costs more to run than standard full nodes.

## Networks Without Standard Archive Access

Before a backfill, test the specific method at the oldest block you need. See [historical query troubleshooting](https://www.dwellir.com/docs/getting-started/troubleshooting#does-an-archive-endpoint-support-every-historical-method).

Some chains on Dwellir currently expose full nodes on the standard platform rather than archive nodes. You can still:

- query current state
- submit transactions
- read recent blocks and receipts
- use normal RPC integrations with SDKs like ethers.js, viem, Web3.js, and polkadot.js

If you need deep historical access on a chain that currently shows `Full` in the Supported Chains catalog, contact the team for dedicated node cluster options.

## How to Decide Quickly

Use this rule of thumb:

- querying the present or the recent past: full node
- querying arbitrary historical state or traces: archive node

If you are unsure, check the method you plan to call. In Dwellir docs, trace/debug-heavy methods call out archive requirements explicitly.

## Related Guides

- [Supported Chains](https://www.dwellir.com/docs/getting-started/supported-chains)
- [Getting Started](https://www.dwellir.com/docs/getting-started)
- [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits)
- [Tracing](https://www.dwellir.com/docs/getting-started/tracing)
- [What is blockchain indexing? Indexers vs archive nodes](https://www.dwellir.com/blog/what-is-blockchain-indexing)

---

## API Authentication

# API Authentication

Dwellir accepts `X-Api-Key` or an API key in the endpoint URL path for HTTP and WebSocket connections. gRPC clients must use lowercase `x-api-key` request metadata.

Use the header when your tracing or logging system records request URLs. Use the URL path when your client cannot set custom headers.

## Header authentication

### HTTP and JSON-RPC

Set the `X-Api-Key` header on each request:

```bash
export DWELLIR_API_KEY="YOUR_API_KEY"

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ${DWELLIR_API_KEY}" \
  https://api-ethereum-mainnet.n.dwellir.com \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

The header also works with HTTP APIs that use paths after the endpoint host. This example calls the Hyperliquid Info API:

```bash
curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ${DWELLIR_API_KEY}" \
  https://api-hyperliquid-mainnet.n.dwellir.com/info \
  -d '{"type":"perpDexs"}'
```

### WebSocket

Send `X-Api-Key` during the WebSocket upgrade request. This Node.js example uses the `ws` package:

```javascript
import WebSocket from 'ws';

const ws = new WebSocket('wss://api-ethereum-mainnet.n.dwellir.com', {
  headers: {
    'X-Api-Key': process.env.DWELLIR_API_KEY,
  },
});
```

The browser WebSocket API cannot set custom headers. For production browser applications, connect through a backend that adds the header.

Direct URL path authentication exposes the key to every browser user. If you require direct browser access, create a separate key, set a strict quota, and rotate it when needed.

### gRPC

Send the API key as lowercase `x-api-key` request metadata:

```text
x-api-key: YOUR_API_KEY
```

See the [Sui gRPC authentication examples](https://www.dwellir.com/docs/sui/grpc-overview#authentication) for TypeScript, Python, and Go clients.

## URL path authentication

Add the API key after the endpoint host when your client cannot set custom headers:

```text
https://api-{network}.n.dwellir.com/YOUR_API_KEY
wss://api-{network}.n.dwellir.com/YOUR_API_KEY
```

Both forms use the same API key, quotas, and usage accounting.

Do not place a reusable server key in browser code. Browser users can read any key sent in the URL.

## Restrict a key by source IP

Authentication proves a request carries a valid key. It does not prove the request came from you. Add [IP whitelisting](https://www.dwellir.com/docs/getting-started/ip-whitelisting) so the key only works from source addresses you own.

Manage whitelists in the [IP Whitelisting tab](https://dashboard.dwellir.com/api-keys?tab=ip-whitelisting). A key with no enabled whitelist is unrestricted by IP. A restricted key denies everything else with HTTP 403 before the request reaches a node, so blocked traffic costs nothing.

Whitelisting suits server-side workloads with stable egress addresses. It cannot restrict browser or mobile clients. See [When to use IP whitelisting](https://www.dwellir.com/guides/when-to-use-ip-whitelisting) for that split.

## Protect the key in telemetry

Header authentication prevents the API key from appearing in the request URL. It does not hide the key from tools that record request headers.

Configure your logs, traces, reverse proxies, and error reports to redact `X-Api-Key`. Store the key in an environment variable or secret manager. Do not commit it to source control.

---

## API key IP whitelisting

# API key IP whitelisting

A leaked API key works from any network. An IP whitelist limits the key to addresses you control, such as an office NAT, a VPN egress, or a server.

Create and assign the whitelist in the [IP Whitelisting tab](https://dashboard.dwellir.com/api-keys?tab=ip-whitelisting). For when the control helps, and when it blocks your own traffic, see [When to use IP whitelisting](https://www.dwellir.com/guides/when-to-use-ip-whitelisting).

## Create a whitelist

1. Open the [IP Whitelisting tab](https://dashboard.dwellir.com/api-keys?tab=ip-whitelisting).
2. Start a new whitelist.
3. Enter a **Name**, such as `production-egress`.
4. Add each IPv4 or IPv6 address as its own row.
5. Assign the whitelist to specific keys, or apply it account-wide.
6. Leave **Enabled** on if you want the restriction to start after you save.
7. Select **Create whitelist**.

The dashboard stores each row as an exact host. It does not accept CIDR ranges. If you need a range, [contact support](mailto:support@dwellir.com).

You cannot enable an empty whitelist. You also cannot assign it or apply it account-wide.

To edit a whitelist later, open it and select **Save whitelist**. Changes take effect within two minutes.

The Dwellir CLI cannot create or assign IP whitelists.

## Apply account-wide or per key

Select **Apply account-wide to all current and future API keys** if every key in the account should inherit the whitelist. New keys get the same restriction when you create them.

To cover only some keys, leave that checkbox off. Then pick those keys in **Assigned API keys**.

If you assign more than one whitelist, a request is allowed when the source IP matches an address on any of them.

If you turn account-wide off later, inherited assignments go away. Manual per-key assignments stay.

Delete a whitelist to remove it from the keys that used it.

## How enforcement works

A key stays unrestricted by IP until it has at least one enabled assignment to an enabled whitelist.

After that, the requester IP must match at least one enabled entry from those whitelists.

A disabled whitelist does not restrict traffic. A disabled assignment does not restrict traffic.

Dwellir checks the source IP before body parsing, usage accounting, rate limiting, and routing. Blocked requests never reach a node. They do not count toward usage, quotas, or rate limits.

The API key table shows the state:

- **Unrestricted** means no policy applies.
- **Inactive policy** means the assigned whitelist is disabled.
- The whitelist name means the policy is active.

## What a blocked request looks like

HTTP, WebSocket, and gRPC-Web denials return HTTP 403. Native gRPC denials return `PermissionDenied`. WebSocket denials happen on the upgrade request.

Every protocol uses this message:

```
Request blocked: source IP <ip> is not whitelisted for this API key. Review or update IP whitelisting at https://dashboard.dwellir.com/api-keys?tab=ip-whitelisting.
```

Unrelated 403 responses stay generic. Only this denial links to the IP Whitelisting tab.

## Add observed source IPs

The create and edit dialog lists source IPs seen in the last 30 days. Each row shows a request count and how many keys saw that IP.

If you add an observed IP, the dashboard creates an exact-host entry. It never adds those addresses on its own. Confirm the address belongs to you before you add it. A leaked key puts someone else's address on that list too.

The list shows recent source IPs for your keys. It may not include every request. Treat your own inventory as the source of truth.

## Before you enable it

An incomplete list blocks your own production traffic. Inventory every address that uses the key before you enable a whitelist on a live key. Include every NAT gateway, every region, and both IPv4 and IPv6. Test the policy on a second key first.

- Browser and mobile clients cannot be whitelisted. Whitelist the backend that proxies their requests instead.
- Dynamic egress breaks the list. Autoscaling workers, serverless platforms, and consumer ISP connections change addresses. Route them through a fixed egress, or leave those keys unrestricted and bound by a quota.
- IPv6 counts separately. A host that reaches Dwellir over IPv6 needs its IPv6 address on the list even when the IPv4 address is already there.
- If your own proxy sits in front of Dwellir, Dwellir sees the proxy. Do not rely on a client-supplied `X-Forwarded-For` header.

If a key already leaked, restrict it first, then rotate it. An IP whitelist limits where an old key still works. It does not replace rotation.

## Troubleshooting

| Symptom                                                                     | Cause                                                   | Fix                                                                                           |
| --------------------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| Production traffic gets 403 with the source-IP message right after enabling | An egress address is missing from the list              | Add the address named in the message, or disable the whitelist while you finish the inventory |
| A new key is restricted unexpectedly                                        | An account-wide whitelist was inherited at key creation | Remove the assignment on that key, or turn off account-wide                                   |
| An address was added but requests are still blocked                         | The change has not propagated yet                       | Retry after two minutes                                                                       |
| Every request on a key is blocked                                           | The assigned whitelist has no usable entries            | Add at least one address, or disable the whitelist                                            |
| Requests are allowed from an address you removed                            | The whitelist or the assignment is disabled             | Re-enable the whitelist and its assignment                                                    |

## Related pages

- [When to use IP whitelisting](https://www.dwellir.com/guides/when-to-use-ip-whitelisting)
- [API authentication](https://www.dwellir.com/docs/getting-started/authentication)
- [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits)
- [API key management](https://www.dwellir.com/docs/cli/api-keys)

---

## Shared Node Pricing

# Shared Node Pricing

The fairest pricing in the industry! 1 RPC Response = 1 API Credit. No compute units to calculate! Add unlimited team members, use trace and debug methods, and pay by card or crypto on all of our paid plans.

You can now pay in crypto on every paid plan: Developer, Growth, Scale, and Enterprise, plus Unlimited Nodes and dedicated node clusters.

## Plans Overview

| Feature                       | Free             | Developer             | Growth            | Scale                    | Enterprise               |
| ----------------------------- | ---------------- | --------------------- | ----------------- | ------------------------ | ------------------------ |
| **Price**                     | **Free**         | **$49**/month         | **$299**/month    | **$999**/month           | **Custom**               |
| **Pay in Crypto**             | N/A              | ✅                     | ✅                 | ✅                        | ✅                        |
| **Best For**                  | Getting started  | Individual developers | Growing teams     | High-traffic apps        | Enterprise scale         |
| **Rate Limit**                | 20 responses/sec | 100 responses/sec     | 500 responses/sec | 5000 responses/sec       | Custom                   |
| **API Credits**               | 100K daily limit | 25M/month             | 150M/month        | 500M/month               | Custom                   |
| **Blockchains**               | 150+             | 150+                  | 150+              | 150+                     | 150+                     |
| **HTTP API**                  | ✅                | ✅                     | ✅                 | ✅                        | ✅                        |
| **WebSocket API**             | ✅                | ✅                     | ✅                 | ✅                        | ✅                        |
| **Trace APIs**                | ❌                | ✅                     | ✅                 | ✅                        | ✅                        |
| **Debug APIs**                | ❌                | ✅                     | ✅                 | ✅                        | ✅                        |
| **`eth_getLogs` block range** | Not available    | 500 blocks            | 10,000 blocks     | 10,000 blocks by default | 10,000 blocks by default |
| **Autoscaling**               | ❌                | ✅                     | ✅                 | ✅                        | ✅                        |
| **Support**                   | Community        | Chat                  | Dedicated Manager | Dedicated Manager        | Priority                 |
| **Extra Credits**             | N/A              | $5 per million        | $3 per million    | $2 per million           | Volume discounts         |
| **Custom SLA**                | ❌                | ❌                     | ❌                 | ❌                        | ✅                        |
| **Dedicated Infrastructure**  | ❌                | ❌                     | ❌                 | ❌                        | ✅                        |

[Contact Sales](https://www.dwellir.com/contact) for Enterprise custom pricing.

See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) for `eth_getLogs` block ranges and pagination guidance.

## What Makes Our Pricing Fair?

### No Compute Units

We dislike compute units as much as you do. At Dwellir:

- **1 RPC response = 1 API credit**
- Even for expensive trace and debug methods
- No surprise bills at the end of the month
- Simple, predictable pricing

What a response costs never changes with the method. What does change with your
plan is how much work fits in one request: an `eth_getLogs` scan wider than your
plan's block range is split into several requests, and each one is billed as a
response. A backfill therefore costs proportionally more on a plan with a
smaller limit, so size it against the
[block-range limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits)
before you commit to a plan for an indexing workload.

### WebSocket Pricing

WebSocket connections are billed the same way as HTTP requests - simple and transparent:

- **1 WebSocket response = 1 API credit**
- You are only charged for responses you receive, not for maintaining the connection
- Real-time subscriptions (like new block headers or pending transactions) count each notification as one response
- Same pricing applies whether you use HTTP or WebSocket APIs
- No additional fees or compute unit multipliers for WebSocket connections

### Transparent Billing

- No hidden fees
- All costs clearly outlined
- Set usage limits per API key to avoid overages
- Real-time usage tracking in dashboard

### Flexible Plans

- Upgrade or downgrade anytime
- Changes take effect at the next billing cycle
- Monthly billing for all paid plans
- Extra credits billed at end of month at per-unit rate

## Unlimited Nodes

If your traffic is high and steady, metered credits stop being the cheapest or the most predictable option. An [Unlimited Node](https://www.dwellir.com/docs/getting-started/unlimited-node-pricing) is a single endpoint with the meter switched off, for a flat monthly price. Tiers run from 25 to 1,000 requests per second and start at $119/month. That endpoint consumes no credits and has no overage exposure.

## Burst Protection

All plans include burst protection using the token bucket algorithm:

- Exceed your rate limit for short periods
- Automatic burst capacity included
- Helps handle legitimate traffic spikes
- No additional charges for burst usage

## Included in All Paid Plans

- ✅ Pay by card or crypto
- ✅ Access to 150+ blockchain networks
- ✅ Unlimited team members
- ✅ Trace and debug methods, billed at 1 credit per response like any other method
- ✅ WebSocket connections
- ✅ Archive node access (select networks)
- ✅ Real-time analytics dashboard
- ✅ API key management
- ✅ Usage alerts

## Billing FAQ

### How does billing work?

We bill monthly for your chosen plan. Any extra credits used beyond your plan's allocation are billed at the end of the month at the per-unit rate specific to your plan.

### Can I set spending limits?

Yes! You can set usage limits for each API key to avoid unexpected charges. Once a key reaches its limit, requests will be blocked until you increase the limit or the next billing cycle begins.

### What payment methods do you accept?

- Credit/debit cards (all major providers)
- Bank transfers (Enterprise plans)
- Cryptocurrency (all paid plans)

### Is there a free trial?

Start with our Free plan to test our infrastructure.

## Ready to Get Started?

[Create an Account](https://dashboard.dwellir.com/register) and get your API key in minutes!

---

## Rate Limits

# Rate Limits

Rate limits ensure fair usage and optimal performance for all users. Understanding and managing your rate limits is crucial for building reliable applications.

## Rate Limits by Plan

| Features                         | Free | Developer  | Growth     | Scale      |
| -------------------------------- | ---- | ---------- | ---------- | ---------- |
| **Price**                        | Free | $49/mo     | $299/mo    | $999/mo    |
| **Overages**                     | ✗    | $5/million | $3/million | $2/million |
| **Responses per second**         | 20   | 100        | 500        | 5,000      |
| **Responses per second (burst)** | ✗    | 500        | 2,500      | 10,000     |

## eth\_getLogs block-range limits

These limits apply to each `eth_getLogs` request over HTTP and WebSocket, separately from responses-per-second limits.

| Plan               | Maximum blocks per request |
| ------------------ | -------------------------: |
| Free               |              Not available |
| Developer          |                        500 |
| Growth             |                     10,000 |
| Scale / Enterprise |          10,000 by default |

Both endpoint blocks count: `toBlock - fromBlock + 1`.
Individual networks may enforce lower limits. Range limits do not guarantee a maximum response size or execution time.
Burst protection does not increase these block limits.

### Choose block bounds

Supply one filter object with block bounds, or use `blockHash` for a single block.
Do not combine a non-null `blockHash` with non-null block bounds.
Use hexadecimal block numbers. The `earliest` tag means block zero.

Missing or null bounds default to `latest`. An empty filter therefore requests one block.
A filter with only `fromBlock` scans toward `latest` and must fit the plan limit.
A filter with only numeric `toBlock` starts at `latest`. If `toBlock` is below the observed head, it returns `-32602`.
Equal tags, including `latest`, `pending`, `safe`, and `finalized`, also request one block where the network supports them.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
The node receives the original tags. Use explicit numeric bounds when you need an exact range width.
Mixed ranges involving `safe` or `finalized` are rejected because their heights depend on the network.

This Developer request covers exactly 500 blocks, from 100 through 599:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_getLogs",
  "params": [{"fromBlock": "0x64", "toBlock": "0x257"}]
}
```

Changing `toBlock` to `0x258` requests 501 blocks and exceeds the Developer limit.
Address and topic filters do not increase the allowed range.

### Split larger ranges

Resolve the ending height once with `eth_blockNumber`, then query consecutive numeric ranges within your plan limit.
For Developer, query blocks 100 through 599, then 600 through 1,099.
Continue from the previous `toBlock + 1` to avoid gaps and overlap.
Reduce the chunk size if the network returns a stricter limit or a timeout.
See the [pagination and backfill guide](https://www.dwellir.com/guides/eth-getlogs-limits) for a scanner example.

### Handle range errors

Range validation errors return HTTP 200 with a JSON-RPC error body. Check the body even when the HTTP request succeeds.

| Condition                                    | JSON-RPC code | Action                                                           |
| -------------------------------------------- | ------------- | ---------------------------------------------------------------- |
| Range exceeds the plan limit                 | `-32005`      | Split the range within the limit named in the message.           |
| Malformed or unmeasurable bounds             | `-32602`      | Supply valid numeric bounds, equal tags, or a single-block hash. |
| Endpoint head unavailable for a tagged bound | `-32000`      | Retry shortly or use explicit numeric bounds.                    |

WebSocket returns the corresponding JSON-RPC error without closing the connection.
These errors differ from HTTP 429 responses caused by request-rate limits.
HTTP 413 indicates an oversized request body, not a block-range rejection.

The same range validation applies to `eth_newFilter` when your plan permits that method.
If any log query fails validation in a batch, the entire batch is rejected before forwarding.
No member executes, including other methods or transaction submissions in that batch.
Violating requests retain their error codes and IDs. Other requests with IDs receive `-32000` indicating that the batch did not execute.
Notifications receive no JSON-RPC response. Rejected batches containing only notifications return HTTP 204.

## Scope: Per Account, Not Per Key

**Rate limits apply to your account as a whole.** Every API key on an account
draws from the same limit, so creating additional keys divides your existing
budget rather than adding to it.

This surprises people often enough to be worth stating plainly:

| Assumption                                      | Reality                                         |
| ----------------------------------------------- | ----------------------------------------------- |
| A new key gets its own responses/second         | All keys on the account share one limit         |
| Splitting traffic across keys raises throughput | It does not — the ceiling is the account's      |
| A new workload is isolated from production      | It competes with production on the same account |

### Why It Matters

Adding a workload to an account that already runs production traffic makes the
two compete. A backfill, a new chain integration, or a long-lived gRPC
subscription can exhaust the shared budget and throttle a service that was
running comfortably before — with no change to that service at all.

This is most visible on streaming endpoints, where a single subscription can
sustain a high message rate indefinitely. A new Aptos transaction stream and an
existing Sui checkpoint subscription on the same account share one limit, and the
noisier one will throttle the quieter one.

If two workloads must not compete, the limit is not something you can separate
after the fact with a second key. Either run them on **separate accounts**, or
size the plan for their **combined** peak rate before going live.

### What You Can Still Scope Per Key

Per-key controls exist, but they cap spend rather than reserve throughput:

- **Usage quotas** — daily or monthly caps, set per key at
  [dashboard.dwellir.com/api-keys](https://dashboard.dwellir.com/api-keys). These
  stop a runaway workload from consuming the account's budget, which is the
  closest thing to isolation within a single account.
- **Per-key analytics** — attribute consumption to a workload at
  [dashboard.dwellir.com/usage](https://dashboard.dwellir.com/usage), so you can
  see which key is causing contention.
- **[Unlimited Nodes](https://www.dwellir.com/docs/getting-started/unlimited-node-pricing)** — a fixed
  requests-per-second tier dedicated to one endpoint, outside the shared account
  limit entirely.

Use quotas to bound the damage, separate accounts or an unlimited node to
guarantee headroom.

## Token Bucket Algorithm

Dwellir uses the **token bucket algorithm** for rate limiting, providing flexible and fair request handling with burst protection.

### How It Works

The token bucket algorithm works like a bucket that:

1. **Holds tokens** - Each token represents permission to make one request
2. **Has a maximum capacity** - The bucket can hold up to your burst limit
3. **Refills at a constant rate** - Tokens are added at your plan's responses/second rate
4. **Consumes tokens per request** - Each API call removes one token

```
┌─────────────────────────┐
│     Token Bucket        │
│                         │
│  Capacity: 500 tokens   │  ← Burst capacity
│  Current: 350 tokens    │
│  Refill: 100 tokens/s   │  ← Your plan's rate
│                         │
└─────────────────────────┘
         ↓
    API Response
    (consumes 1 token)
```

### Benefits of Token Bucket

1. **Burst Handling** - Handle traffic spikes gracefully
2. **Smooth Rate Limiting** - No hard cutoffs at exact intervals
3. **Fair Usage** - Unused capacity accumulates for later use
4. **Predictable Behavior** - Easy to understand and plan for

### Example Scenarios

#### Scenario 1: Steady Traffic

- Plan: Developer (100 responses/s)
- Usage: 80 responses/s consistently
- Result: ✅ All requests succeed, 20 tokens/s accumulate up to burst limit

#### Scenario 2: Traffic Burst

- Plan: Developer (100 responses/s, 500 burst capacity)
- Usage: 300 responses/s for 1 second
- Result: ✅ All requests succeed using burst tokens
- Recovery: Need to stay under 100 responses/s to refill

#### Scenario 3: Sustained Overuse

- Plan: Developer (100 responses/s)
- Usage: 150 responses/s sustained
- Result: ⚠️ After burst depletes, 50 responses/s are rate limited

## Request Counting

### What Counts as a Response?

Each of the following counts as **1 API response**:

- Standard JSON-RPC calls (`eth_getBalance`, `eth_call`, etc.)
- Batch requests count as the number of calls in the batch
- WebSocket messages (both sent and received)
- **Even trace and debug methods** (no compute unit multipliers!)
- gRPC unary calls, and **each message delivered on a gRPC stream**

For streaming endpoints the billed unit is the message the server sends, not the
subscription. A Sui `SubscribeCheckpoints` subscription counts one per checkpoint
delivered; an Aptos `GetTransactions` stream counts one per `TransactionsResponse`
batch, including the progress-only messages a filtered stream emits. There is no
cap on concurrent subscriptions — the limit applies to the messages they deliver,
pooled across the account.

## Handling Rate Limit Errors

When you exceed your rate limit, you'll receive a 429 HTTP status code with the following response:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32005,
    "message": "Rate limit exceeded"
  },
  "id": 1
}
```

## Setting Usage Limits

Protect yourself from unexpected charges by setting limits per API key:

1. Go to [dashboard.dwellir.com/api-keys](https://dashboard.dwellir.com/api-keys)
2. Click the edit icon (✏️) next to your API key
3. Set daily or monthly quotas
4. Click "Update API Key" to save

When a quota is reached, the API will return a 429 error until the quota resets.

## Monitoring Your Usage

### Dashboard Analytics

Track your usage in real-time at [dashboard.dwellir.com/usage](https://dashboard.dwellir.com/usage):

- Current responses/second
- Daily and monthly usage
- Per-method breakdown
- Geographic distribution

### API Access

For programmatic access to usage data, please [contact our team](https://www.dwellir.com/contact).

## Need Higher Limits?

If you need higher rate limits:

1. **Upgrade Your Plan** - Check if a higher tier meets your needs
2. **[Unlimited Nodes](https://www.dwellir.com/docs/getting-started/unlimited-node-pricing)** - Buy a fixed requests-per-second tier for one endpoint and stop consuming credits on it
3. **Contact Support** - Request custom limits within your current plan
4. **Enterprise Solutions** - Get custom infrastructure and limits

When requesting increases, provide:

- Current usage patterns
- Expected growth timeline
- Peak traffic requirements
- Use case description

[Contact our team](https://www.dwellir.com/contact) for custom rate limits.

---

## Sticky Sessions

# Sticky Sessions

Dwellir endpoints are backed by multiple blockchain nodes behind a load balancer. By default, each request may land on a different node. Sticky sessions let you pin all your requests to the **same backend node** using a cookie, which is important when your workflow depends on consistent state across sequential calls.

## When You Need Sticky Sessions

- **Filter-based workflows** -- `eth_newFilter` / `eth_getFilterChanges` require the same node because filters are local to the node that created them.
- **Pending transaction monitoring** -- `eth_newPendingTransactionFilter` followed by `eth_getFilterChanges`.
- **Debug and trace sequences** -- multi-step trace workflows where intermediate state lives on a single node.
- **Any stateful JSON-RPC sequence** -- whenever a later call depends on state created by an earlier call on the same node.

WebSocket connections are inherently sticky because they maintain a single long-lived TCP connection to one backend. Sticky sessions are only relevant for HTTP requests.

## How It Works

1. **First request** (no cookie) -- the load balancer picks a healthy backend node, serves the response, and returns a `Set-Cookie` header:

   ```
   Set-Cookie: DWSESSION=<node-id>; Path=/; Max-Age=604800; SameSite=Lax
   ```

2. **Subsequent requests** -- your HTTP client sends the cookie back. The load balancer routes the request to the same node. No new `Set-Cookie` is returned when the session is maintained.

3. **Cookie expiry** -- the cookie is valid for 7 days (`Max-Age=604800`). After that, the next request is treated as a first request and a new node is assigned.

## Usage Examples

### cURL

```bash
# Step 1: Make the first request and save the cookie
curl -c cookies.txt -X POST \
  -H "Content-Type: application/json" \
  https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -d '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"fromBlock":"latest"}],"id":1}'

# Step 2: Subsequent requests reuse the cookie
curl -b cookies.txt -X POST \
  -H "Content-Type: application/json" \
  https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -d '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":["0x1"],"id":2}'
```

### Python (requests)

```python
import requests

url = "https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY"

# Use a Session -- it stores and sends cookies automatically
session = requests.Session()

# First request receives the DWSESSION cookie
response = session.post(url, json={
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{"fromBlock": "latest"}],
    "id": 1
})
filter_id = response.json()["result"]

# Subsequent requests send the cookie and hit the same node
response = session.post(url, json={
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": [filter_id],
    "id": 2
})
```

### JavaScript (fetch)

```javascript
// In browsers, fetch sends cookies automatically with credentials: "include"
const url = "https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY";

const response = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",
  body: JSON.stringify({
    jsonrpc: "2.0",
    method: "eth_newFilter",
    params: [{ fromBlock: "latest" }],
    id: 1,
  }),
});

const { result: filterId } = await response.json();

// The browser stores the DWSESSION cookie and sends it on the next request
const changes = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",
  body: JSON.stringify({
    jsonrpc: "2.0",
    method: "eth_getFilterChanges",
    params: [filterId],
    id: 2,
  }),
});
```

### Node.js (ethers.js / web3.js)

Standard provider classes in ethers.js and web3.js do not send cookies. If your workflow requires sticky sessions from a Node.js backend, use a cookie-aware HTTP client like the Python `requests.Session` example above, or use a WebSocket connection which is inherently sticky:

```javascript
import { WebSocketProvider } from "ethers";

// WebSocket connections are always sticky -- single TCP connection to one node
const provider = new WebSocketProvider(
  "wss://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY"
);

const filterId = await provider.send("eth_newFilter", [
  { fromBlock: "latest" },
]);
const changes = await provider.send("eth_getFilterChanges", [filterId]);
```

## Important Notes

- **Health takes priority** -- if your pinned node becomes unhealthy (e.g., falls behind on block height), the load balancer may route you to a different node and return a new `Set-Cookie`. This is by design to avoid sending requests to a degraded node.
- **Not a guarantee** -- sticky sessions are best-effort. Always handle the case where your session-dependent call fails (e.g., filter not found) by re-creating the filter.
- **WebSocket is simpler** -- if your use case allows it, prefer WebSocket connections. They are inherently sticky and also support server-pushed subscriptions like `eth_subscribe`.
- **Cookie scope** -- the `DWSESSION` cookie is scoped to `Path=/`, so it applies to all requests to the same endpoint domain. If you use multiple chains, each domain gets its own independent cookie.

---

## Supported Chains

# Supported Chains

Browse every supported chain from one place. Chains with dedicated docs pages open in docs, while the rest link to their network overview pages until deeper docs land.

## Overview

- Supported chains: 111
- Docs-ready landing pages: 58
- Archive-backed chains: 84
- Ecosystem groups: 4

## Helpful Links

- [Getting Started](https://www.dwellir.com/docs/getting-started)
  Start with API keys, endpoint URLs, and your first request.
- [Archive Nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)
  Learn when you need archive nodes and how to identify historical-state workloads.
- [Endpoint Format](https://www.dwellir.com/docs/getting-started#endpoint-url-format)
  Use the standard HTTPS and WebSocket endpoint patterns across chains.
- [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits)
  Review plan limits, quotas, burst behavior, and handling 429 responses.

## Chain Index

### [Acala](https://www.dwellir.com/docs/acala)

Acala: Leading finance backend with DEX, aUSD stablecoin, and seamless updates. Compatible with Polkadot & Ethereu…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/acala)

### [Acurast](https://www.dwellir.com/networks/acurast)

Explore Acurast's decentralized serverless cloud, leveraging mobile devices to create a global network for secure…

- Ecosystem: Substrate
- Networks: canary, mainnet
- Node access: Archive
- Docs page: Not yet available

### [Ajuna Network](https://www.dwellir.com/networks/ajuna-polkadot)

On-chain game logic and player-owned assets on a Polkadot parachain, with Unity, Unreal, and .NET SDKs for game cl…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Aleph Zero](https://www.dwellir.com/networks/aleph-zero)

Aleph Zero, providing a scalable and secure blockchain environment with a focus on privacy and developer friendlin…

- Ecosystem: Substrate
- Networks: mainnet, testnet
- Node access: Archive
- Docs page: Not yet available

### [Aleph Zero EVM](https://www.dwellir.com/networks/aleph-zero-evm)

Explore Aleph Zero EVM, offering EVM compatibility on the Aleph Zero blockchain for a seamless smart contract deve…

- Ecosystem: EVM
- Networks: mainnet, testnet
- Node access: Full
- Docs page: Not yet available

### [Amplitude](https://www.dwellir.com/networks/amplitude)

Amplitude is a community-driven, AMPE-powered network on Kusama, serving as a testing ground for Pendulum applicat…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Aptos](https://www.dwellir.com/networks/aptos)

Explore Aptos: a high-performance Layer 1 blockchain providing secure, fast, and developer-friendly infrastructure…

- Ecosystem: Move
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Arbitrum](https://www.dwellir.com/docs/arbitrum)

Arbitrum is an Optimistic Rollup chain for Ethereum, which means it is a Layer 2 scaling solution for Ethereum.

- Ecosystem: EVM
- Networks: mainnet, one, sepolia
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/arbitrum)

### [Arc](https://www.dwellir.com/docs/arc)

Build payment and settlement applications on Arc with Dwellir's EVM-compatible RPC, WebSocket access, and generate…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/arc)

### [Asset Hub](https://www.dwellir.com/docs/asset-hub)

Explore Asset Hub, the Polkadot system parachain for streamlined asset creation, management, and cross-chain trans…

- Ecosystem: Substrate
- Networks: kusama, mainnet, paseo, polkadot, westend
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/asset-hub)

### [Astar](https://www.dwellir.com/docs/astar)

Astar is a multi-chain smart contract platform that supports multiple blockchains and virtual machines.

- Ecosystem: Substrate
- Networks: mainnet, shibuya testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/astar)

### [Avalanche](https://www.dwellir.com/docs/avalanche)

Avalanche is an open-source platform for launching decentralized finance applications and enterprise blockchain de…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/avalanche)

### [Aventus](https://www.dwellir.com/networks/aventus)

Explore Aventus: a fast, secure Polkadot parachain offering enterprise-grade tooling for NFTs, digital assets, and…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [BalanceAI](https://www.dwellir.com/networks/balanceai)

Discover BalanceAI: an open-source protocol for decentralized AI model distribution, autonomous agent collaboratio…

- Ecosystem: Other
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Base](https://www.dwellir.com/docs/base)

Explore Base, a secure and low-cost Ethereum L2 solution, built to make Ethereum accessible to everyone, with feat…

- Ecosystem: EVM
- Networks: mainnet, sepolia
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/base)

### [Basilisk](https://www.dwellir.com/networks/basilisk)

Basilisk's mission is to create frictionless liquidity bootstrapping for new cryptoassets.

- Ecosystem: Substrate
- Networks: canary, mainnet
- Node access: Archive
- Docs page: Not yet available

### [Berachain](https://www.dwellir.com/docs/berachain)

Discover how BeraChain is pushing the boundaries of blockchain efficiency and functionality.

- Ecosystem: EVM
- Networks: bartio, bepolia testnet, mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/berachain)

### [Bifrost](https://www.dwellir.com/docs/bifrost)

Bifrost has developed a Staking Liquidity Protocol that provides cross-chain liquidity for staked assets.

- Ecosystem: Substrate
- Networks: kusama, mainnet, polkadot
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/bifrost)

### [Binance Smart Chain](https://www.dwellir.com/docs/bsc)

Binance Smart Chain is a blockchain network built for running smart contract-based applications.

- Ecosystem: EVM
- Networks: mainnet, testnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/bsc)

### [Bitcoin](https://www.dwellir.com/networks/bitcoin)

Read blocks, unspent outputs, and fee estimates, and broadcast transactions through unpruned Bitcoin Core nodes wi…

- Ecosystem: Other
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Bittensor](https://www.dwellir.com/docs/bittensor)

Discover Bittensor's innovative platform for decentralized AI communication and collaboration.

- Ecosystem: Substrate
- Networks: mainnet, testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/bittensor)

### [Blast](https://www.dwellir.com/docs/blast)

Explore Blast's blockchain solutions, offering new possibilities for asset ownership and in-game economies.

- Ecosystem: EVM
- Networks: mainnet, sepolia
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/blast)

### [Boba Network](https://www.dwellir.com/docs/boba-network)

Access Boba Network's hybrid compute-powered L2 infrastructure for building advanced dApps with seamless Web2 inte…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/boba-network)

### [Bridge Hub](https://www.dwellir.com/docs/bridge-hub)

Explore Bridge Hub, Polkadot's system parachain for trustless bridging, on-chain light clients, and seamless cross…

- Ecosystem: Substrate
- Networks: kusama, mainnet, paseo, polkadot, westend
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/bridge-hub)

### [Celo](https://www.dwellir.com/docs/celo)

Explore Celo's unique features, including its stablecoin platform and mobile-centric design aimed at broadening fi…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/celo)

### [Centrifuge](https://www.dwellir.com/docs/centrifuge)

Discover Centrifuge, the first protocol to tokenize real-world assets, offering a decentralized infrastructure for…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/centrifuge)

### [Chainflip](https://www.dwellir.com/networks/chainflip)

Read the Chainflip State Chain that settles native BTC, ETH, SOL, and DOT swaps through a Just-In-Time AMM run by…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Chiliz](https://www.dwellir.com/docs/chiliz)

Chiliz Chain offers a platform for developers to explore Chiliz Fan Tokens with 150+ sports IPs, using 11 validato…

- Ecosystem: EVM
- Networks: mainnet, spicy testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/chiliz)

### [Collectives](https://www.dwellir.com/networks/collectives)

Discover Polkadot Collectives: on-chain groups for collaborative governance, customizable parameters, and funding…

- Ecosystem: Substrate
- Networks: mainnet, polkadot, westend
- Node access: Archive
- Docs page: Not yet available

### [Coretime](https://www.dwellir.com/networks/coretime)

Discover Coretime's elastic resource model for purchasing reserved or on-demand blockspace on Polkadot.

- Ecosystem: Substrate
- Networks: kusama, mainnet, polkadot, westend
- Node access: Archive
- Docs page: Not yet available

### [Cronos](https://www.dwellir.com/docs/cronos)

Cronos is a utility token designed by Crypto.com to facilitate transactions within its blockchain and financial ec…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/cronos)

### [Crust Network](https://www.dwellir.com/networks/crust-network)

Explore how Crust Network is revolutionizing cloud storage by providing decentralized, privacy-focused, and reliab…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Darwinia](https://www.dwellir.com/networks/darwinia)

Darwinia introduces an Ethereum-compatible chain that boasts faster transaction speeds and reduced fees, paired wi…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [elysium](https://www.dwellir.com/networks/elysium-mainnet)

- Ecosystem: EVM
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Elysium](https://www.dwellir.com/networks/elysium)

Explore Elysium testnet, Kinetiq's Arbitrum Orbit L2 for Hyperliquid. It settles to HyperEVM, uses HYPE for gas, a…

- Ecosystem: EVM
- Networks: testnet
- Node access: Archive
- Docs page: Not yet available

### [Energy Web X](https://www.dwellir.com/networks/energy-web-x)

Explore Energy Web X's decentralized network, enabling innovative energy solutions through coordinated worker node…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Enjin](https://www.dwellir.com/docs/enjin)

Enjin offers a suite of integrated products that make non-fungible tokens (NFTs) easy for individuals, businesses,…

- Ecosystem: Substrate
- Networks: mainnet, matrixchain, relaychain
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/enjin)

### [Ethereum](https://www.dwellir.com/docs/ethereum)

Ethereum is the biggest and most popular network for smart contracts.

- Ecosystem: EVM
- Networks: holesky, mainnet, sepolia
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/ethereum)

### [Etherlink](https://www.dwellir.com/docs/etherlink)

Etherlink mainnet archive RPC over HTTPS and WebSocket from two sites in Sweden.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/etherlink)

### [Fantom](https://www.dwellir.com/networks/fantom)

Fantom is a fast, high-throughput open-source smart contract platform for digital assets and dApps.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Filecoin](https://www.dwellir.com/networks/filecoin)

Explore Filecoin's decentralized storage network, enabling secure and efficient data storage through a peer-to-pee…

- Ecosystem: Other
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Flow EVM Gateway](https://www.dwellir.com/docs/flow-evm-gateway)

Discover Flow, the blockchain designed for the next generation of decentralized applications, providing scalabilit…

- Ecosystem: EVM
- Networks: mainnet, mainnet latest spork, testnet latest spork
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/flow-evm-gateway)

### [Frequency](https://www.dwellir.com/networks/frequency)

The Frequency Project, empowering and educating on the benefits of intentional frequency, offering audio and visua…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Gnosis](https://www.dwellir.com/docs/gnosis)

Explore Gnosis Chain, an EVM compatible, community-owned Layer 1 network secured by 165k+ validators, with trust-m…

- Ecosystem: EVM
- Networks: chiado testnet, mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/gnosis)

### [Gravity Alpha](https://www.dwellir.com/networks/gravity-alpha)

Explore Gravity Alpha's innovative blockchain platform, designed for mass adoption and an omnichain future with un…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Heima](https://www.dwellir.com/networks/heima)

Heima abstracts complexity across accounts, chains, and agents, providing a unified interface for cross-chain DeFi…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Humanode](https://www.dwellir.com/networks/humanode)

Build dApps with built-in human uniqueness checks on Humanode's EVM-compatible biometric network.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Hydration](https://www.dwellir.com/docs/hydration)

HydraDX is a Substrate-based, open, and permissionless cross-chain liquidity protocol for the Polkadot ecosystem.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/hydration)

### [Hyperbridge Nexus](https://www.dwellir.com/networks/hyperbridge-nexus)

Explore Hyperbridge for institutional-grade, secure cross-chain communication powered by zero-knowledge proofs.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Hyperliquid](https://www.dwellir.com/docs/hyperliquid)

Explore Hyperliquid: a high-performance blockchain for next-generation DeFi, offering on-chain spot and perpetuals…

- Ecosystem: EVM
- Networks: hyperevm mainnet, mainnet, testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/hyperliquid)

### [Immutable](https://www.dwellir.com/docs/immutable)

Launch Web3 games on Immutable's zkEVM featuring native marketplace integrations and player-owned asset economies.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/immutable)

### [Ink](https://www.dwellir.com/docs/ink)

Build DeFi applications on Ink with Dwellir's EVM-compatible RPC, WebSocket access, and generated JSON-RPC method…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/ink)

### [Integritee](https://www.dwellir.com/networks/integritee)

Integritee is enabling firms to utilize data without compromising privacy, powered by Integritee's Polkadot parach…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Interlay](https://www.dwellir.com/networks/interlay)

Interlay is a decentralized layer-1 network, powered by and optimized for Bitcoin

- Ecosystem: Substrate
- Networks: kintsugi canary, mainnet
- Node access: Archive
- Docs page: Not yet available

### [IoTeX](https://www.dwellir.com/docs/iotex)

Access IoTeX's high-performance blockchain built for IoT and DePIN applications, featuring 5-second blocks, 2000+…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/iotex)

### [Karura](https://www.dwellir.com/networks/karura)

Explore Karura's DeFi solutions, providing comprehensive financial services on the Kusama network.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Krest](https://www.dwellir.com/networks/krest)

Discover how Krest Network facilitates innovation by providing a safe environment for testing and deploying decent…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Kusama](https://www.dwellir.com/docs/kusama)

Kusama to deliver a scalable network for fast innovation.

- Ecosystem: Substrate
- Networks: canary, encointer canary, mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/kusama)

### [Liberland](https://www.dwellir.com/networks/liberland)

Discover Liberland's innovative approach to nation-building through the use of blockchain for decentralized govern…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Linea](https://www.dwellir.com/docs/linea)

Explore Linea's architecture and its role in scaling Ethereum's performance through innovative zkEVM technology an…

- Ecosystem: EVM
- Networks: mainnet, sepolia
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/linea)

### [LISK](https://www.dwellir.com/docs/lisk)

Discover Lisk, the blockchain application platform that simplifies blockchain development with a user-friendly SDK…

- Ecosystem: EVM
- Networks: mainnet, sepolia testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/lisk)

### [Litentry](https://www.dwellir.com/networks/litentry)

EVM-compatible Polkadot parachain, formerly Litentry, with one omni-account and intent-based execution across Ethe…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Manta Atlantic](https://www.dwellir.com/docs/manta-atlantic)

Discover Manta Atlantic's ZK Layer 1 blockchain, offering scalable and privacy-focused solutions for on-chain comp…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/manta-atlantic)

### [Manta Pacific](https://www.dwellir.com/docs/manta-pacific)

Explore Manta Network's modular blockchain platform, designed for scalable and privacy-focused dApps utilizing zer…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/manta-pacific)

### [Mantle](https://www.dwellir.com/docs/mantle)

Discover Mantle's unique Layer-2 solution for Ethereum, featuring a modular architecture, efficient data availabil…

- Ecosystem: EVM
- Networks: mainnet, sepolia testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/mantle)

### [MegaETH](https://www.dwellir.com/docs/megaeth)

MegaETH is a real-time Ethereum Layer-2 blockchain streaming transactions at lightning speed.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/megaeth)

### [Monad](https://www.dwellir.com/docs/monad)

Monad is a high-performance, EVM-compatible Layer 1 blockchain designed to scale to 10,000 TPS.

- Ecosystem: EVM
- Networks: mainnet, testnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/monad)

### [Movement](https://www.dwellir.com/networks/movement)

Explore Movement's innovative blockchain platform, offering enhanced security, performance, and user experience th…

- Ecosystem: Move
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Mythos](https://www.dwellir.com/networks/mythos)

Discover Mythos for an integrated gaming experience with seamless NFT integration and robust blockchain support.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Neuroweb](https://www.dwellir.com/docs/neuroweb)

Neuroweb represents the forefront of AI and blockchain convergence, aiming to enhance network intelligence.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/neuroweb)

### [Nodle](https://www.dwellir.com/networks/nodle)

Nodle's mission is to connect a trillion things to the Internet, by leveraging Bluetooth Low Energy via smartphone…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [opBNB](https://www.dwellir.com/docs/opbnb)

Discover opBNB, the OP Stack-based layer 2 that scales BNB Chain with low-cost, high-throughput EVM transactions.

- Ecosystem: EVM
- Networks: mainnet, testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/opbnb)

### [Optimism](https://www.dwellir.com/docs/optimism)

Discover Optimism, an Ethereum L2 solution offering a fast, stable, and scalable blockchain, built to efficiently…

- Ecosystem: EVM
- Networks: mainnet, sepolia testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/optimism)

### [Paseo](https://www.dwellir.com/networks/paseo)

Discover how Paseo Network supports developers with a decentralized and reliable testnet for building and testing…

- Ecosystem: Substrate
- Networks: mainnet, testnet
- Node access: Archive
- Docs page: Not yet available

### [Peaq](https://www.dwellir.com/networks/peaq)

Explore how Peaq is shaping the future of machine economy with its innovative decentralized network.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Pendulum](https://www.dwellir.com/networks/pendulum)

Explore Pendulum Chain's blockchain technology designed for modern financial infrastructure, offering interoperabi…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [People Kusama](https://www.dwellir.com/networks/people-kusama)

Discover People - Kusama for innovative identity solutions with low staking requirements and experimental features.

- Ecosystem: Substrate
- Networks: canary, mainnet
- Node access: Archive
- Docs page: Not yet available

### [People Polkadot](https://www.dwellir.com/networks/people-polkadot)

Explore People - Polkadot for secure, human-readable identity management and social recovery solutions on Polkadot.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [People Westend](https://www.dwellir.com/networks/people-westend)

Explore People - Westend for a risk-free environment to test and innovate identity system enhancements.

- Ecosystem: Substrate
- Networks: mainnet, testnet
- Node access: Archive
- Docs page: Not yet available

### [Phala](https://www.dwellir.com/networks/phala)

Phala Network tackles the issue of trust in the computation cloud, by build around TEE-based privacy technology th…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Plasma](https://www.dwellir.com/docs/plasma)

Connect to Plasma Mainnet Beta through Dwellir HTTPS and WebSocket RPC. EVM Layer 1 for stablecoin payments. Chain…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/plasma)

### [Polkadot](https://www.dwellir.com/docs/polkadot)

Polkadot to deliver the most robust platform for security, scalability and innovation.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/polkadot)

### [Polygon](https://www.dwellir.com/docs/polygon)

Polygon is a protocol and a framework for building and connecting Ethereum-compatible blockchain networks.

- Ecosystem: EVM
- Networks: amoy, mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/polygon)

### [Pulsechain](https://www.dwellir.com/docs/pulsechain)

Build on Pulse Chain's Ethereum-forked network featuring native asset duplication and gas-efficient smart contract…

- Ecosystem: EVM
- Networks: mainnet, testnet v4
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/pulsechain)

### [Robinhood](https://www.dwellir.com/docs/robinhood)

Robinhood Chain is an Ethereum-compatible Arbitrum Nitro Layer 2 focused on tokenized real-world assets.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/robinhood)

### [Robonomics](https://www.dwellir.com/networks/robonomics)

Discover how Robonomics Network is revolutionizing the interaction between humans and machines in the IoT ecosyste…

- Ecosystem: Substrate
- Networks: canary, mainnet
- Node access: Archive
- Docs page: Not yet available

### [Ronin](https://www.dwellir.com/docs/ronin)

Discover Ronin, the EVM-compatible blockchain crafted for game developers to create scalable and secure player-own…

- Ecosystem: EVM
- Networks: mainnet, saigon testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/ronin)

### [Scroll](https://www.dwellir.com/docs/scroll)

Deploy Ethereum dApps on Scroll's zkEVM with zero code changes and enhanced transaction privacy.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/scroll)

### [Shiden](https://www.dwellir.com/networks/shiden)

Shiden Network is a multi-chain dApps hub on Kusama. It supports Ethereum Virtual Machine, WebAssembly, and Layer2…

- Ecosystem: Substrate
- Networks: canary, mainnet
- Node access: Archive
- Docs page: Not yet available

### [Sonic](https://www.dwellir.com/docs/sonic)

Deploy ultra-fast dApps on Sonic's EVM-compatible chain featuring liquid staking mechanics and cross-chain asset b…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/sonic)

### [Sora](https://www.dwellir.com/networks/sora)

Explore SORA's innovative decentralized economic system, featuring adaptive monetary policies and democratic on-ch…

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Stable](https://www.dwellir.com/networks/stable)

Stable is an institutional-grade blockchain designed for stablecoin payments, featuring native USDT settlement and…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Starknet](https://www.dwellir.com/networks/starknet)

Explore StarkNet's robust Layer 2 blockchain technology, designed for enhancing Ethereum's scalability while maint…

- Ecosystem: Other
- Networks: mainnet, sepolia testnet
- Node access: Archive
- Docs page: Not yet available

### [Sui](https://www.dwellir.com/networks/sui)

Explore Sui's high-performance blockchain. Sign up now to access Dwellir's Sui RPC nodes and accelerate your Web3…

- Ecosystem: Move
- Networks: mainnet, testnet
- Node access: Full
- Docs page: Not yet available

### [Taiko](https://www.dwellir.com/docs/taiko)

Access Taiko mainnet through Dwellir's archive RPC endpoint over HTTPS and WebSocket.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/taiko)

### [Tangle](https://www.dwellir.com/networks/tangle)

Explore the capabilities of Tangle in advancing Web3 technology through enhanced developer tools and protocols.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Tempo](https://www.dwellir.com/docs/tempo)

Build payment rails, treasury automation, and stablecoin-native apps on Tempo with Dwellir's mainnet RPC, trace AP…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/tempo)

### [TON](https://www.dwellir.com/networks/ton)

Explore The Open Network's innovative blockchain platform, offering scalable solutions and fostering a decentraliz…

- Ecosystem: Other
- Networks: mainnet, testnet
- Node access: Full
- Docs page: Not yet available

### [TRON](https://www.dwellir.com/docs/tron)

Discover TRON for decentralized digital content distribution and a vibrant ecosystem of dApps.

- Ecosystem: Other
- Networks: mainnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/tron)

### [Unichain](https://www.dwellir.com/docs/unichain)

Deploy low-latency DeFi applications on Unichain's Superchain-aligned rollup with native cross-chain asset bridgin…

- Ecosystem: EVM
- Networks: mainnet, sepolia testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/unichain)

### [Unique Network](https://www.dwellir.com/networks/unique)

Protocol-level NFTs on Polkadot with nesting, re-fungible shares, sponsored fees, and an EVM for Solidity tooling.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: Not yet available

### [Viction](https://www.dwellir.com/docs/viction)

Discover Viction's people-centric blockchain platform, providing zero-gas transactions and fostering a secure and…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/viction)

### [Waves](https://www.dwellir.com/networks/waves)

Access Waves' high-throughput blockchain with predictable smart contract execution, sponsored fees, and enterprise…

- Ecosystem: Other
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Westend](https://www.dwellir.com/networks/westend)

Polkadot's protocol test network and the first chain to receive runtime upgrades. WND is free from the faucet and…

- Ecosystem: Substrate
- Networks: testnet
- Node access: Archive
- Docs page: Not yet available

### [World Chain](https://www.dwellir.com/docs/world-chain)

World Chain is an Ethereum L2 blockchain prioritizing verified humans with free gas, fast transactions, and sybil-…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/world-chain)

### [XDC Network](https://www.dwellir.com/docs/xdc-network)

Explore XDC Network: a high-performance blockchain powering next-generation DeFi, trade finance, and asset tokeniz…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/xdc-network)

### [XX Network](https://www.dwellir.com/docs/xx-network)

Discover the xx network, pioneering decentralized, private, and fast communication and payment solutions.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/xx-network)

### [Zeitgeist](https://www.dwellir.com/networks/zeitgeist)

Zeitgeist is an evolving blockchain for prediction markets and futarchy.

- Ecosystem: Substrate
- Networks: mainnet
- Node access: Full
- Docs page: Not yet available

### [Zetachain](https://www.dwellir.com/docs/zetachain)

Discover how Zetachain is paving the way for blockchain interoperability with innovative cross-chain technology.

- Ecosystem: EVM
- Networks: mainnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/zetachain)

### [zkSync Era](https://www.dwellir.com/docs/zksync-era)

Discover zkSync Era for high throughput, low-cost transaction processing with complete EVM compatibility powered b…

- Ecosystem: EVM
- Networks: mainnet
- Node access: Full
- Docs page: [Available](https://www.dwellir.com/docs/zksync-era)

### [Zora](https://www.dwellir.com/docs/zora)

Explore Zora Network's commitment to redefining digital media and commerce on the blockchain.

- Ecosystem: EVM
- Networks: mainnet, sepolia testnet
- Node access: Archive
- Docs page: [Available](https://www.dwellir.com/docs/zora)

---

## Tracing

# Tracing

Transaction tracing allows you to inspect the internal operations of smart contract executions, debug failed transactions, and analyze gas consumption patterns.

## Overview

Tracing APIs provide detailed information about:

- EVM execution steps
- Internal transactions
- State changes
- Gas consumption
- Opcode execution
- Storage modifications

## Available Tracing Methods

### debug\_traceTransaction

Trace a single transaction by hash.

> **Example data:** The curl commands below use Ethereum block `0x166eaba` and transaction `0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198` captured on 2025-10-06. Replace them with your own values when tracing different operations.

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": [
      "0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198",
      {
        "tracer": "callTracer",
        "tracerConfig": {
          "onlyTopCall": false
        }
      }
    ],
    "id": 1
  }'
```

### debug\_traceBlockByNumber

Trace all transactions in a block.

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0x166eaba", {"tracer": "callTracer"}],
    "id": 1
  }'
```

### trace\_transaction

Get trace information for a transaction (Parity/OpenEthereum style).

```bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198"],
    "id": 1
  }'
```

## Tracer Types

### 1. Call Tracer

Captures all calls made during transaction execution.

```javascript
{
  "tracer": "callTracer",
  "tracerConfig": {
    "onlyTopCall": false,
    "withLog": true
  }
}
```

**Output includes:**

- Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- From/to addresses
- Input/output data
- Gas used
- Error messages

### 2. Prestate Tracer

Shows state before transaction execution.

```javascript
{
  "tracer": "prestateTracer",
  "tracerConfig": {
    "diffMode": true
  }
}
```

**Output includes:**

- Account balances
- Contract code
- Storage values
- Nonce values

### 3. 4byte Tracer

Identifies function signatures in the transaction.

```javascript
{
  "tracer": "4byteTracer"
}
```

**Output:**

- Map of 4-byte signatures to call counts

### 4. Custom JavaScript Tracer

Create custom tracers for specific analysis.

```javascript
{
  "tracer": "{data: [], step: function(log) { this.data.push(log.op.toString()); }, result: function() { return this.data; }}"
}
```

## Practical Examples

### Debugging Failed Transactions

```javascript
async function debugFailedTransaction(txHash) {
  const trace = await provider.send('debug_traceTransaction', [
    txHash,
    { tracer: 'callTracer' }
  ]);
  
  // Find the exact failure point
  function findError(call) {
    if (call.error) {
      return {
        address: call.to,
        error: call.error,
        input: call.input
      };
    }
    if (call.calls) {
      for (const subcall of call.calls) {
        const error = findError(subcall);
        if (error) return error;
      }
    }
    return null;
  }
  
  return findError(trace);
}
```

### Analyzing Gas Usage

```javascript
async function analyzeGasUsage(txHash) {
  const trace = await provider.send('debug_traceTransaction', [
    txHash,
    { tracer: 'callTracer' }
  ]);
  
  function calculateGas(call, depth = 0) {
    const gasInfo = {
      address: call.to,
      gasUsed: parseInt(call.gasUsed, 16),
      depth: depth,
      calls: []
    };
    
    if (call.calls) {
      for (const subcall of call.calls) {
        gasInfo.calls.push(calculateGas(subcall, depth + 1));
      }
    }
    
    return gasInfo;
  }
  
  return calculateGas(trace);
}
```

### Internal Transactions

```javascript
async function getInternalTransactions(txHash) {
  const trace = await provider.send('trace_transaction', [txHash]);
  
  return trace
    .filter(t => t.type === 'call' && t.action.value !== '0x0')
    .map(t => ({
      from: t.action.from,
      to: t.action.to,
      value: t.action.value,
      success: t.result !== null
    }));
}
```

## Performance Considerations

### Archive Node Requirements

Tracing requires archive nodes for historical data:

- Full state at every block
- Complete transaction history
- Higher infrastructure costs

### Request Optimization

1. **Cache Trace Results**

```javascript
const traceCache = new Map();

async function getCachedTrace(txHash) {
  if (traceCache.has(txHash)) {
    return traceCache.get(txHash);
  }
  
  const trace = await provider.send('debug_traceTransaction', [
    txHash,
    { tracer: 'callTracer' }
  ]);
  
  traceCache.set(txHash, trace);
  return trace;
}
```

2. **Batch Trace Requests**

```javascript
async function batchTraceTransactions(txHashes) {
  const requests = txHashes.map((hash, index) => ({
    jsonrpc: '2.0',
    method: 'debug_traceTransaction',
    params: [hash, { tracer: 'callTracer' }],
    id: index
  }));
  
  return await provider.send(requests);
}
```

3. **Use Appropriate Tracers**

- `callTracer` for debugging
- `prestateTracer` for state analysis
- `4byteTracer` for function identification
- Custom tracers for specific needs

## Error Handling

Common tracing errors and solutions:

### Missing State

```json
{
  "error": {
    "code": -32000,
    "message": "missing trie node"
  }
}
```

**Solution**: Use an archive node or request more recent data.

### Timeout

```json
{
  "error": {
    "code": -32000,
    "message": "execution timeout"
  }
}
```

**Solution**: Simplify tracer or reduce block range.

### Invalid Tracer

```json
{
  "error": {
    "code": -32602,
    "message": "invalid tracer"
  }
}
```

**Solution**: Check tracer syntax and supported tracers for the network.

## Security Considerations

When using tracing:

1. **Validate Input**: Sanitize transaction hashes and parameters
2. **Rate Limit**: Implement client-side rate limiting
3. **Access Control**: Restrict tracing access in production
4. **Data Privacy**: Traced data may contain sensitive information

## Tools and Libraries

### Web3.js

```javascript
const trace = await web3.currentProvider.send({
  method: 'debug_traceTransaction',
  params: [txHash, { tracer: 'callTracer' }]
});
```

### Ethers.js

```javascript
const trace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
```

### Cast (Foundry)

```bash
cast run --trace 0xhash --rpc-url https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY
```

Need help with tracing? [Contact our support team](https://www.dwellir.com/contact).

---

## RPC troubleshooting and account questions

# RPC troubleshooting and account questions

Use this guide to diagnose common Remote Procedure Call (RPC) problems. Start with the response body, endpoint, and method.

## Why does my request return an access error?

| Response                           | Check                                                            | Next step                                                                                                                                                                                                |
| ---------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401` or `403`                     | Key, account access, endpoint access, and source IP restrictions | Confirm the key is enabled in the [dashboard](https://dashboard.dwellir.com). Check [authentication](https://www.dwellir.com/docs/getting-started/authentication) and [IP whitelisting](https://www.dwellir.com/docs/getting-started/ip-whitelisting). |
| `403` for one method               | Method access or a restricted RPC namespace                      | Check the method's chain reference and your account's access. A working `eth_blockNumber` does not prove access to `debug_*` or `trace_*`.                                                               |
| `405`                              | HTTP method                                                      | Use the endpoint's documented method. Send a JSON-RPC request with `POST` and `Content-Type: application/json`.                                                                                          |
| `413`                              | Request body size                                                | Reduce the payload or split the batch. Check the response body before treating this as a block-range error.                                                                                              |
| `429`                              | Account throughput or key quota                                  | Check [rate limits](https://www.dwellir.com/docs/getting-started/rate-limits), reduce concurrency, and retry with exponential backoff and jitter.                                                                               |
| HTTP `200` with a JSON-RPC `error` | Backend or method error                                          | Read the `error.code` and `error.message`. HTTP success does not mean the RPC call succeeded.                                                                                                            |

Dwellir's gateway uses `403` for IP restrictions, endpoint access, and method access. Read the response body before diagnosing the cause.

Do not rely on `401` alone to detect authentication failures. Opening an endpoint in a browser sends `GET`, without a JSON-RPC request body.

Permitted HTTP methods depend on the service. A browser request does not, by itself, explain a `405` response.

Test a basic method on the same endpoint with the same key. If it works, compare the failing method, parameters, and access requirements.

Never put an API key in a support screenshot or public issue. Redact keys from endpoint URLs, headers, and logs.

## Why is a method missing or forbidden?

JSON-RPC error `-32601` means the method does not exist on that backend. A gateway `403` means the request failed an access check.

Check the [supported chain](https://www.dwellir.com/docs/getting-started/supported-chains) and its method reference. Client libraries can probe optional methods that the chain does not implement.

Use a supported fallback when your client permits one. Retrying an unsupported method does not make it available.

For tracing, check [tracing support](https://www.dwellir.com/docs/getting-started/tracing). Archive state, tracing, and historical proofs are separate capabilities.

## Why do several keys hit the same limit?

API keys on one account share the account's throughput limit. Creating more keys does not multiply that limit.

Each key can also have daily and monthly quotas. Check both the account limit and the key quota in the dashboard.

A JSON-RPC batch counts each subrequest. WebSocket and gRPC usage includes delivered messages, so subscriptions can consume usage without new HTTP calls.

See [request counting and streaming limits](https://www.dwellir.com/docs/getting-started/rate-limits#request-counting). Reduce subscriptions or filter their scope when you receive more data than you need.

## Why does eth\_getLogs fail for a large range?

The block-range limit is separate from request throughput. Split queries into supported ranges using [the range rules](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

Block bounds are inclusive. For a maximum of `N` blocks, use `toBlock = fromBlock + N - 1`.

Advance the next range to the previous `toBlock + 1`. Inspect each batch result for errors before storing it as a successful page.

## Why do filters disappear or return no changes?

An HTTP filter belongs to the backend that created it. Preserve the `DWSESSION` cookie across creation and polling with [sticky sessions](https://www.dwellir.com/docs/getting-started/sticky-sessions).

Node.js `fetch` does not maintain a browser cookie jar. Use a cookie-aware client or explicitly preserve the session cookie.

Create each filter after establishing its session. Concurrent filter workflows must preserve the cookie associated with each filter.

A backend restart, session change, or expired filter can invalidate the filter ID. Recreate it and backfill missed blocks where the method supports historical queries.

An empty result means no matching changes were returned. It does not prove that the chain exposes a public mempool or a sequencer's pending transactions.

## Does an archive endpoint support every historical method?

No. Historical state, transaction history, tracing, and proof generation have different requirements.

Check the specific method at the oldest block your application needs. A recent `eth_call` does not verify a genesis query or historical `eth_getProof`.

Record the requested block and validate the returned state against known historical values. Do not silently replace a failed historical query with `latest`.

See [archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes) for the distinction between full and archive nodes.

## Does a nearby gateway guarantee a nearby blockchain node?

No. The gateway and blockchain backend are separate parts of the request path. Backend availability depends on the chain and endpoint.

A `DWSESSION` cookie preserves backend affinity where possible. It does not select a geographic region, and backend health can override affinity.

Measure requests from your application's actual location. Record response time and the returned block or checkpoint together.

Compare providers at the same block or checkpoint. A faster response with older state can give your application less current data.

## Where do I manage my account?

| Task                               | Dashboard location                                                                                               |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Create, enable, or rotate a key    | API Keys                                                                                                         |
| Change your plan or manage add-ons | [Settings, Plan](https://dashboard.dwellir.com/settings?tab=planChange)                                          |
| Stop a paid base plan              | Open Settings, Plan as the primary account owner and choose the Free plan. Confirm the displayed effective date. |
| Cancel an add-on                   | Open Settings, Plan and use the cancellation control for that active add-on. Check its access end date.          |
| View invoices and payment settings | [Settings, Billing](https://dashboard.dwellir.com/settings?tab=billing)                                          |
| Update company details             | [Settings, Account](https://dashboard.dwellir.com/settings?tab=account)                                          |
| Manage teammates                   | [Settings, Team members](https://dashboard.dwellir.com/settings?tab=team)                                        |

Some actions require the account owner or an authorized account role. A missing control can reflect your permissions.

Disabling a key does not cancel a subscription or add-on. Confirm the cancellation status and effective date in the account controls.

## What should I include when reporting a remaining problem?

Check [service status](https://status.dwellir.com/) first. If the problem remains, email <support@dwellir.com> with:

- The endpoint host and chain, without the key.
- The method, parameters, and a minimal reproduction.
- The UTC time, source region, HTTP status, and full error body.
- The requested block or checkpoint and the returned position.
- For streams, the subscription and last processed cursor.

Include a request identifier if the response provides one. These details distinguish access, routing, retention, and backend failures.

---

## Unlimited Node Pricing

# Unlimited Node Pricing

An Unlimited Node is a single Dwellir endpoint with the meter switched off. While it is active, requests through that endpoint stop drawing on your plan's monthly API credit allowance. The endpoint is capped at the requests per second you chose instead, and you pay one fixed monthly price with no per-response billing.

It sits between [shared node plans](https://www.dwellir.com/docs/getting-started/pricing) and [dedicated node clusters](https://www.dwellir.com/dedicated-clusters). You get more headroom than a plan allowance, with far less commitment than private infrastructure.

Unlimited Nodes are not available for Hyperliquid. Use the gRPC or Order Book add-on on an API plan, or a Dedicated Node Cluster. See [Hyperliquid pricing](https://www.dwellir.com/docs/hyperliquid/pricing).

## The ladder

Five rungs, priced at a flat $4.80 per RPS per month. There are no in-between steps.

| Tier         | Monthly price | Requests per month | Effective cost per million | Metered equivalent at $2.00/M | Saving |
| ------------ | ------------- | ------------------ | -------------------------- | ----------------------------- | ------ |
| **25 RPS**   | **$119**      | 65M/mo             | $1.83                      | $130                          | 8%     |
| **100 RPS**  | **$479**      | 260M/mo            | $1.84                      | $520                          | 8%     |
| **250 RPS**  | **$1,199**    | 650M/mo            | $1.84                      | $1,300                        | 8%     |
| **500 RPS**  | **$2,399**    | 1.3B/mo            | $1.85                      | $2,600                        | 8%     |
| **1000 RPS** | **$4,799**    | 2.6B/mo            | $1.85                      | $5,200                        | 8%     |

Prices are monthly USD list, per node, exclusive of tax. Pricing version `2026-08-13`.

### Where the comparison comes from

```
rps × 2,600,000 seconds × $2.00 per million responses = metered equivalent
```

The metered equivalent is what the same throughput would cost at the Scale plan's per-million rate if you ran at your RPS limit for a whole month. That is $5.20 per RPS per month, against the Unlimited Node's $4.80. It is the spend an Unlimited Node replaces, not an invented list price. The headline saving only lands if you run near your cap. The flat bill is the other half of the value.

Use the [calculator](https://www.dwellir.com/pricing?nodes=unlimited) to work out where your own workload lands.

## What an Unlimited Node is

### Unmetered requests

Requests through the endpoint no longer consume API credits. There is no credit counter to watch, no month-end throttling, and no compute-unit multiplier on trace or debug methods. That matches Dwellir's normal billing, where 1 response = 1 credit on every method.

### An upper limit, not a guarantee

The RPS figure is the cap the gateway enforces. It is **not** a throughput guarantee. Beneath the cap you get whatever the cluster behind the endpoint can serve. If you need contractually guaranteed throughput, that is a dedicated node cluster.

### The cap binds both ways

An Unlimited Node runs at its own RPS limit **even when your plan's rate limit is higher**. A Scale plan account (5,000 RPS) with a 100 RPS Unlimited Node gets 100 RPS on that endpoint. Pick the rung that matches your real peak.

### One node, one endpoint

An Unlimited Node covers one endpoint route. Unmetering a second endpoint means a second Unlimited Node. That lets you move one hot path to an Unlimited Node and leave everything else on the shared plan.

### Shared pool, not dedicated hardware

Unlimited Nodes are served from Dwellir's shared node pool. Dedicated hardware, custom regions, and a custom SLA are a separate product.

### Premium endpoints

Buying an Unlimited Node on a locked premium endpoint adds the required premium add-on to the same purchase, as a second line item.

## Exceeding the limit

The gateway rate limits requests above your limit and returns the standard 429 response:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32005,
    "message": "Rate limit exceeded"
  },
  "id": 1
}
```

Nothing is charged at request time, so there is no way to run up an unexpected bill. Handle 429s the same way you would on a shared plan. See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits) for retry and backoff guidance.

## Billing mechanics

|                     |                                                                                                      |
| ------------------- | ---------------------------------------------------------------------------------------------------- |
| **First charge**    | Prorated for the remainder of the current cycle, then the full monthly price from the next boundary. |
| **Tax**             | Quoted at checkout, not included in the list prices above.                                           |
| **Payment**         | Card or crypto. Crypto payment is available on every plan.                                           |
| **Downgrades**      | Take effect at the period boundary. The limit you paid for holds until then.                         |
| **Upgrades**        | Not self-serve. [Contact support](https://www.dwellir.com/contact) and we credit the unused period.  |
| **Cancellation**    | Recurs monthly until you cancel. Access runs to the end of the paid period.                          |
| **Price integrity** | Every quote carries its pricing version. Checkout rejects a stale client price.                      |

## Choosing between the options

|                    | Shared nodes                | Unlimited Nodes            | Dedicated node clusters   |
| ------------------ | --------------------------- | -------------------------- | ------------------------- |
| **Billing**        | Per response, plus overages | Flat monthly, per node     | Flat monthly, per cluster |
| **Requests**       | Capped by plan allowance    | Unlimited within your tier | Unlimited                 |
| **Throughput**     | 20 to 5,000 RPS by plan     | 25 to 1,000 RPS tiers      | Sized to the workload     |
| **Infrastructure** | Shared node pool            | Shared node pool           | Isolated, redundant nodes |
| **Overage risk**   | Real                        | None                       | None                      |
| **Region choice**  | Automatic routing           | Automatic routing          | You pick the regions      |
| **SLA**            | Standard                    | Standard                   | Custom, up to 99.99%      |
| **Entry price**    | Free, then $49/mo           | $119/mo per node           | Quoted per cluster        |
| **Setup**          | Self-serve                  | Self-serve                 | Scoping call              |

Rules of thumb:

- **Overages keep appearing on your bill.** Move the noisy endpoint to an Unlimited Node.
- **Your traffic is spiky but low on average.** Stay on the shared plan. A tier you use 20% of is worse value than credits.
- **You need more than 1,000 RPS, specific regions, or a custom SLA.** Talk to us about a [dedicated node cluster](https://www.dwellir.com/dedicated-clusters).

## Getting started

1. Open your endpoint in [the dashboard](https://dashboard.dwellir.com).
2. Make it an Unlimited Node and pick the tier that covers your peak.
3. Keep using the same endpoint URL and API key. Nothing about the request path changes.

Questions about sizing? [Contact our team](https://www.dwellir.com/contact).

---

## Gnosis Chain - Ethereum Sidechain

# Gnosis Chain - Ethereum Sidechain

## Gnosis RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Gnosis supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Gnosis Chain?

Gnosis Chain is a community-owned, fully decentralized Ethereum sidechain designed for stable and accessible DeFi. Built and maintained by the Gnosis community, Gnosis Chain offers:

### **Predictable Transaction Costs**

- **xDAI native token** - USD-pegged stablecoin for stable gas fees
- **5-second block times** - Fast and predictable confirmations
- **Low-cost transactions** - Typical fees under $0.01

### **True Decentralization**

- **140,000+ validators** - World's most decentralized Proof-of-Stake network
- **Community governance** - No single entity controls the chain
- **Battle-tested security** - Over 3 years of continuous operation

### **Mature Ecosystem**

- **$200M+ TVL** - Established DeFi protocols
- **EVM compatibility** - Full Ethereum tooling support
- **Bridge ecosystem** - Native bridges to Ethereum and other chains

## Quick Start with Gnosis Chain

Connect to Gnosis Chain in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Gnosis Chain mainnet
const provider = new JsonRpcProvider(
  'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance (returns xDAI balance)
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString(), 'wei (xDAI)');
```

```javascript
const Web3 = require('web3');

// Connect to Gnosis Chain mainnet
const web3 = new Web3(
  'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Gnosis Chain:', chainId === 100);

// Get gas price (in xDAI)
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { gnosis } from 'viem/chains';

// Create Gnosis Chain client
const client = createPublicClient({
  chain: gnosis,
  transport: http('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 100       | Mainnet      |
| Block Time   | 5 seconds | Average      |
| Gas Token    | xDAI      | USD-pegged   |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Gnosis Chain supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with sidechain-specific optimizations.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation on Gnosis Chain
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Gnosis Chain has 5-second blocks for fast confirmations
  console.log('Transaction confirmed in ~5 seconds');

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Gnosis Chain:

```javascript
// Gas estimation on Gnosis Chain
const gasEstimate = await provider.estimateGas(tx);

// xDAI has predictable pricing (~$1.00)
const gasPrice = await provider.getGasPrice();
const costInXDAI = gasEstimate * gasPrice / BigInt(1e18);

console.log(`Transaction cost: ${costInXDAI} xDAI (~$${costInXDAI})`);
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 3000; // Gnosis Chain recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class GnosisProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds"

Gnosis Chain transactions require xDAI for gas:

```javascript
// Check xDAI balance before transactions
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  const shortage = ethers.formatEther(totalRequired - balance);
  throw new Error(`Need ${shortage} more xDAI`);
}
```

### Error: "Transaction underpriced"

Gnosis Chain uses EIP-1559 pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Gnosis Chain requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Gnosis Chain)
const provider = new JsonRpcProvider(
  'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (100)
// Note: Native token is xDAI (not ETH)
// Note: 5-second block times (faster than Ethereum)
```

## Resources & Tools

### Official Resources

- [Gnosis Chain Documentation](https://docs.gnosischain.com)
- [Gnosis Chain Bridge](https://bridge.gnosischain.com)
- [Gnosis Chain Block Explorer](https://gnosisscan.io)

### Developer Tools

- [Hardhat Config](https://docs.gnosischain.com/tools/hardhat)
- [Foundry Setup](https://docs.gnosischain.com/tools/foundry)
- [Remix Integration](https://docs.gnosischain.com/tools/remix)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Top Gnosis Chain RPC Providers 2026](https://www.dwellir.com/blog/best-gnosis-rpc-providers)

***

*Start building on Gnosis Chain with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Gnosis RPC Method

# debug_traceBlock - Gnosis RPC Method

Traces all transactions in a block on Gnosis by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Gnosis - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Gnosis
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Gnosis:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Gnosis blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/gnosis/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/gnosis/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Gnosis RPC Method

# debug_traceBlockByHash - Gnosis RPC Method

Traces all transactions in a block on Gnosis identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Gnosis - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Gnosis
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Gnosis:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Gnosis:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/gnosis/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/gnosis/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/gnosis/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/gnosis/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Gnosis RPC Method

# debug_traceBlockByNumber - Gnosis RPC Method

Traces all transactions in a block on Gnosis identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Gnosis - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Gnosis execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Gnosis:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Gnosis:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/gnosis/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/gnosis/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/gnosis/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Gnosis RPC Method

# debug_traceCall - Gnosis RPC Method

Traces a call on Gnosis without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Gnosis - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Gnosis
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
        "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
        "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    data: '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    data: '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    'data': '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
        "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Gnosis to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Gnosis:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Gnosis:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/gnosis/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/gnosis/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Gnosis RPC Method

# debug_traceTransaction - Gnosis RPC Method

Traces a transaction execution on Gnosis by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Gnosis
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/gnosis/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/gnosis/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Gnosis RPC Method

# eth_accounts - Gnosis RPC Method

Returns a list of addresses owned by the client on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for prediction market builders, DAO tooling developers, and teams building MEV-protected applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/gnosis/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/gnosis/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Gnosis RPC Method

# eth_blockNumber - Gnosis RPC Method

Returns the number of the most recent block on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_blockNumber` is fundamental for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Syncing Applications** - Keep your dApp in sync with the latest Gnosis blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Gnosis block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Gnosis block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Gnosis block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Gnosis block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Gnosis block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Gnosis:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Gnosis:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Gnosis node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/gnosis/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/gnosis/eth_syncing) - Check if node is still syncing

---

## eth_call - Gnosis RPC Method

# eth_call - Gnosis RPC Method

Executes a new message call immediately without creating a transaction on Gnosis. Used for reading smart contract state.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

The `eth_call` method serves these key scenarios for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Gnosis
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';
const walletAddress = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Gnosis. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Gnosis
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Gnosis

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    data := common.FromHex("0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Gnosis RPC Method

# eth_chainId - Gnosis RPC Method

Returns the chain ID used for transaction signing on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_chainId` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/gnosis/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/gnosis/eth_syncing) - Check sync status

---

## eth_coinbase - Gnosis RPC Method

# eth_coinbase - Gnosis RPC Method

Checks the legacy `eth_coinbase` compatibility method on Gnosis. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for prediction market builders, DAO tooling developers, and teams building MEV-protected applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Gnosis coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Gnosis coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Gnosis coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Gnosis coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Gnosis coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Gnosis nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/gnosis/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/gnosis/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/gnosis/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Gnosis RPC Method

# eth_estimateGas - Gnosis RPC Method

Estimates the gas necessary to execute a transaction on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Gnosis
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Gnosis.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Gnosis may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/gnosis/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Gnosis RPC Method

# eth_feeHistory - Gnosis RPC Method

Returns historical gas fee data on Gnosis, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Gnosis without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Gnosis.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Gnosis) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/gnosis/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/gnosis/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Gnosis RPC Method

# eth_gasPrice - Gnosis RPC Method

Returns the current gas price on Gnosis in wei.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Gnosis
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Gnosis. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Gnosis, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Gnosis: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Gnosis supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/gnosis/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/gnosis/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Gnosis RPC Method

# eth_getBalance - Gnosis RPC Method

Returns the balance of a given address on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getBalance` is fundamental for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Gnosis
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Gnosis
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Gnosis. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Gnosis`);
  return balance;
}

displayBalance('0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Gnosis at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Gnosis')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Gnosis')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Gnosis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/gnosis/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/gnosis/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Gnosis RPC Method

# eth_getBlockByHash - Gnosis RPC Method

Returns information about a block by hash on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getBlockByHash` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Gnosis
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Gnosis.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Gnosis.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Gnosis RPC Method

# eth_getBlockByNumber - Gnosis RPC Method

Returns information about a block by block number on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getBlockByNumber` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Gnosis
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Gnosis with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Gnosis. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/gnosis/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/gnosis/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Gnosis RPC Method

# eth_getBlockReceipts - Gnosis RPC Method

Returns all transaction receipts for a block on Gnosis. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getBlockReceipts` is useful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Gnosis, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Gnosis. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xb7d40246868f4037c9d681df4f45634e7b378187531f3ca53b56f97350b622a1",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/gnosis/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/gnosis/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Gnosis RPC Method

# eth_getCode - Gnosis RPC Method

Returns the bytecode at a given address on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getCode` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Gnosis
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Gnosis:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Gnosis:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/gnosis/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/gnosis/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Gnosis RPC Method

# eth_getFilterChanges - Gnosis RPC Method

Polls a filter on Gnosis for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getFilterChanges` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Gnosis
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Gnosis:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/gnosis/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/gnosis/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/gnosis/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/gnosis/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/gnosis/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Gnosis RPC Method

# eth_getFilterLogs - Gnosis RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Gnosis. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getFilterLogs` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Gnosis
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/gnosis/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/gnosis/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/gnosis/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/gnosis/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Gnosis RPC Method

# eth_getLogs - Gnosis RPC Method

Returns an array of all logs matching a given filter object on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Gnosis for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Gnosis
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Gnosis.

```javascript
const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Gnosis enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Gnosis, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/gnosis/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/gnosis/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Gnosis RPC Method

# eth_getStorageAt - Gnosis RPC Method

Returns the value from a storage position at a given address on Gnosis. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getStorageAt` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **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 prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **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": [
    "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "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-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', '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-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';

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-gnosis-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 = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
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-gnosis-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-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    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 Gnosis:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-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-gnosis-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 = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';
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 Gnosis:`);
  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/gnosis/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/gnosis/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/gnosis/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Gnosis RPC Method

# eth_getTransactionByHash - Gnosis RPC Method

Returns the information about a transaction by transaction hash on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getTransactionByHash` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Gnosis
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Gnosis. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Gnosis. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/gnosis/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Gnosis RPC Method

# eth_getTransactionCount - Gnosis RPC Method

Returns the number of transactions sent from an address on Gnosis, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getTransactionCount` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Gnosis
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Gnosis nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
nonce = get_transaction_count(address)
print(f'Gnosis nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Gnosis nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Gnosis:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/gnosis/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/gnosis/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/gnosis/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Gnosis RPC Method

# eth_getTransactionReceipt - Gnosis RPC Method

Returns the receipt of a transaction by transaction hash on Gnosis. Receipt is only available for mined transactions.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_getTransactionReceipt` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Gnosis and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Gnosis. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Gnosis, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/gnosis/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/gnosis/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Gnosis RPC Method

# eth_hashrate - Gnosis RPC Method

Returns the legacy `eth_hashrate` compatibility value on Gnosis. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Gnosis hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Gnosis hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Gnosis hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Gnosis hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Gnosis hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/gnosis/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/gnosis/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Gnosis RPC Method

# eth_maxPriorityFeePerGas - Gnosis RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Gnosis. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Gnosis
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Gnosis priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Gnosis priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Gnosis priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Gnosis:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Gnosis:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/gnosis/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/gnosis/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/gnosis/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Gnosis RPC Method

# eth_mining - Gnosis RPC Method

Checks the legacy `eth_mining` compatibility method on Gnosis. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Gnosis mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Gnosis mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Gnosis mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Gnosis mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Gnosis mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/gnosis/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/gnosis/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Gnosis RPC Method

# eth_newBlockFilter - Gnosis RPC Method

Creates a filter on Gnosis that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_newBlockFilter` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Block Monitoring** - Detect new blocks on Gnosis as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Gnosis:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/gnosis/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/gnosis/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/gnosis/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Gnosis RPC Method

# eth_newFilter - Gnosis RPC Method

Creates a filter object on Gnosis based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_newFilter` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Event Monitoring** - Subscribe to specific contract events on Gnosis such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Gnosis:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/gnosis/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/gnosis/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/gnosis/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/gnosis/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/gnosis/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Gnosis RPC Method

# eth_newPendingTransactionFilter - Gnosis RPC Method

Creates a filter on Gnosis that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on Gnosis to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Gnosis...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Gnosis:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/gnosis/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/gnosis/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/gnosis/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Gnosis RPC Method

# eth_protocolVersion - Gnosis RPC Method

Returns the current Ethereum protocol version used by the Gnosis node.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_protocolVersion` is useful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Gnosis protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Gnosis protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Gnosis protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Gnosis protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Gnosis protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Gnosis nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/gnosis/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/gnosis/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/gnosis/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Gnosis RPC Method

# eth_sendRawTransaction - Gnosis RPC Method

Submits a pre-signed transaction for broadcast to Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Gnosis
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Gnosis mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/gnosis/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/gnosis/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/gnosis/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Gnosis RPC Method

# eth_sendTransaction - Gnosis RPC Method

Creates and sends a new transaction from an unlocked account on Gnosis. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Gnosis tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Gnosis tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Gnosis tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Gnosis tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Gnosis tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Gnosis dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/gnosis/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/gnosis/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Gnosis RPC Method

# eth_signTransaction - Gnosis RPC Method

Signs a transaction with the private key of the specified account on Gnosis without submitting it to the network.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for prediction market builders, DAO tooling developers, and teams building MEV-protected applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Gnosis tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Gnosis tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Gnosis tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Gnosis:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/gnosis/eth_accounts) - List accounts available for signing

---

## eth_syncing - Gnosis RPC Method

# eth_syncing - Gnosis RPC Method

Returns the sync status of your Gnosis node - either `false` when fully synced, or an object describing the sync progress.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_syncing` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Gnosis node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Gnosis node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Gnosis node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/gnosis/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/gnosis/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/gnosis/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Gnosis RPC Method

# eth_uninstallFilter - Gnosis RPC Method

Removes a filter on Gnosis that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`eth_uninstallFilter` is important for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/gnosis/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/gnosis/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/gnosis/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/gnosis/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/gnosis/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Gnosis RPC Method

# net_listening - Gnosis RPC Method

Checks whether the connected Gnosis client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`net_listening` is useful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Gnosis node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Gnosis node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Gnosis node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/gnosis/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/gnosis/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/gnosis/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/gnosis/web3_clientVersion) - Get node client info

---

## net_peerCount - Gnosis RPC Method

# net_peerCount - Gnosis RPC Method

Returns the number of peers currently connected to your Gnosis node.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`net_peerCount` is important for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Gnosis deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Gnosis peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Gnosis peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Gnosis peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Gnosis nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/gnosis/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/gnosis/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/gnosis/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/gnosis/web3_clientVersion) - Get node client info

---

## net_version - Gnosis RPC Method

# net_version - Gnosis RPC Method

Returns the current network ID on Gnosis as a decimal string. The network ID identifies which network the node is connected to.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`net_version` is essential for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Endpoint Identification** - Confirm your application is connected to the expected Gnosis network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Gnosis network ID:', networkId);

// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Gnosis network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Gnosis network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/gnosis/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/gnosis/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/gnosis/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/gnosis/eth_syncing) - Check node sync progress

---

## rpc_modules - Gnosis RPC Method

# rpc_modules - Gnosis RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Gnosis endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`rpc_modules` is useful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/gnosis/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/gnosis/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/gnosis/trace_transaction) - Trace namespace example

---

## trace_block - Gnosis RPC Method

# trace_block - Gnosis RPC Method

Returns traces for all transactions in a block on Gnosis.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Gnosis
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Gnosis chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/gnosis/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/gnosis/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/gnosis/trace_get) - Get a specific trace by index

---

## trace_call - Gnosis RPC Method

# trace_call - Gnosis RPC Method

Traces a call without creating a transaction on Gnosis, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Gnosis
- **Pre-execution analysis** - Test contract interactions without spending gas for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
      "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
    data: '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
        'data': '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/gnosis/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/gnosis/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/gnosis/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Gnosis RPC Method

# trace_callMany - Gnosis RPC Method

Traces multiple calls in sequence on Gnosis, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Gnosis
- **Historical state comparison** - Compare how the same call would execute at different points in Gnosis chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"}, ["trace"]],
      [{"to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", "data": "0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"}, ["trace"]],
        [{"to": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', data: '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d' }, ['trace']],
    [{ to: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', 'data': '0x70a08231000000000000000000000000e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'}, ['trace']],
        [{'to': '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/gnosis/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/gnosis/eth_call) - Execute call without trace

---

## trace_filter - Gnosis RPC Method

# trace_filter - Gnosis RPC Method

Returns traces matching a filter on Gnosis.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Gnosis
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/gnosis/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/gnosis/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/gnosis/eth_getLogs) - Filter event logs

---

## trace_get - Gnosis RPC Method

# trace_get - Gnosis RPC Method

Returns a trace at a specific position within a transaction on Gnosis.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Gnosis
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/gnosis/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/gnosis/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Gnosis RPC Method

# trace_replayBlockTransactions - Gnosis RPC Method

Replays all transactions in a block on Gnosis and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Gnosis
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Gnosis chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/gnosis/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/gnosis/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/gnosis/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Gnosis RPC Method

# trace_replayTransaction - Gnosis RPC Method

Replays a transaction on Gnosis and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Gnosis
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/gnosis/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/gnosis/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/gnosis/trace_block) - Get all traces in a block

---

## trace_transaction - Gnosis RPC Method

# trace_transaction - Gnosis RPC Method

Returns all traces for a specific transaction on Gnosis.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for prediction markets (largest by market cap), Safe wallet infrastructure, CoW Protocol DEX, and Gnosis Pay card integration
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Gnosis
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x299f6371b38ceebe7468ea5ef8bb50ae739dfe4e0aa3dac121e6707e240c9814'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/gnosis/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/gnosis/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/gnosis/trace_filter) - Filter traces by criteria

---

## txpool_content - Gnosis RPC Method

# txpool_content - Gnosis RPC Method

Returns the full pending and queued transaction pool for the connected Gnosis endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`txpool_content` is useful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/gnosis/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/gnosis/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/gnosis/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Gnosis RPC Method

# txpool_status - Gnosis RPC Method

Returns transaction pool counters for the connected Gnosis endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`txpool_status` is valuable for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/gnosis/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/gnosis/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/gnosis/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Gnosis RPC Method

# web3_clientVersion - Gnosis RPC Method

Returns the current client software version string for your Gnosis node, including the client name, version number, OS, and runtime.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

## When to Use This Method

`web3_clientVersion` is valuable for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Gnosis client:', clientVersion);

// Using fetch
const response = await fetch('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Gnosis client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Gnosis client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/gnosis/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/gnosis/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/gnosis/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/gnosis/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Gnosis RPC Method

# web3_sha3 - Gnosis RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Gnosis.

> **Why Gnosis?** Build on the prediction market pioneer with $260M+ TVL and xDAI stablecoin-based gas fees with stablecoin gas fees for predictable costs, Shutter MEV protection, 150K+ Safe wallets, and Circles decentralized UBI protocol.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for prediction market builders, DAO tooling developers, and teams building MEV-protected applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-gnosis-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/gnosis/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/gnosis/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/gnosis/web3_clientVersion) - Get node client version

---

## Hydration Liquidity Parachain RPC Guide

# Hydration Liquidity Parachain RPC Guide

## Hydration RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Hydration supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Hydration?

Hydration powers Polkadot's unified liquidity layer, offering deep cross-chain markets through a single omnipool runtime. Teams choose Hydration because it provides:

### **Unified Liquidity Router**

- Route any XCM-enabled asset through the omnipool without fragmented pairs
- Single-sided provisioning with dynamic fee curves tuned for stable markets
- Built-in MEV protection via adaptive liquidity routing

### **Native Cross-Chain Execution**

- Parachain-level integrations with fast finality on the Polkadot Relay Chain
- Out-of-the-box XCM channels to leading parachains for trustless settlement
- Seamless asset teleportation between Hydration and Kusama's Basilisk network

### **Developer-First Tooling**

- Full Substrate JSON-RPC coverage with archive snapshots for historical queries
- Rich analytics via Hydration Subscan and on-chain telemetry feeds
- Reusable SDK patterns across JavaScript, Rust, and Python ecosystems

## Quick Start with Hydration

Connect to Hydration mainnet or Basilisk testnet in seconds using Dwellir-managed infrastructure.

Basilisk mirrors Hydration's runtime for staging releases on Kusama. Use the Basilisk endpoints for pre-production load tests and fee estimation before promoting to Hydration mainnet.

### Installation & Setup

cURL
JavaScript (polkadot.js)
Rust (subxt)
Python (py-substrate-interface)

```bash
curl https://api-hydration.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "chain_getHeader",
    "params": []
  }'
```

**Expected output (2025-10-01):**

```json
{
  "jsonrpc": "2.0",
  "result": {
    "number": "0x904ae4",
    "hash": "0xd2f7f582eb7170b1a6382641a2ad9625cd46cb292fa0a8a1fc6f2bb6e1ed6b4d",
    "parentHash": "0x2f58fc2a2d7024520d2062142c4d7788146101d0736c7c952866adb17bb25483"
  },
  "id": 1
}
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function main() {
  const provider = new WsProvider('wss://api-hydration.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });

  const [chain, nodeName, version, runtime] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.state.getRuntimeVersion()
  ]);

  console.log(`Connected to ${chain} via ${nodeName} v${version}`);
  console.log(`Runtime specVersion=${runtime.specVersion.toString()}, transactionVersion=${runtime.transactionVersion}`);

  const header = await api.rpc.chain.getHeader();
  console.log(`Latest head #${header.number} (${header.hash.toHex()})`);

  await api.disconnect();
}

main().catch(console.error);
```

```rust
use subxt::{config::substrate::SubstrateConfig, OnlineClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<SubstrateConfig>::from_url(
        "wss://api-hydration.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let block_hash = api.rpc().block_hash(None).await?.expect("block hash");
    let header = api.rpc().header(Some(block_hash)).await?.expect("header");

    println!("Finalized block #{}", header.number);
    println!("State root {}", header.state_root);

    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(
    url="wss://api-hydration.n.dwellir.com/YOUR_API_KEY",
    type_registry_preset="substrate-node-template"
)

chain = substrate.get_chain_head()
print("Latest finalized head:", chain)

runtime = substrate.get_runtime_version()
print("specVersion:", runtime['specVersion'], "transactionVersion:", runtime['transactionVersion'])

account = substrate.query(
    module='System',
    storage_function='Account',
    params=['5FUNjmP7L2nA9dZ1VnoqeY3SFqHZ3MQNrZjSxFv6YWza7yeb']
)
print("Account free balance:", account.value['data']['free'])
```

## Network Information

| Parameter                | Hydration Mainnet                                                    | Basilisk Testnet                                                     |
| ------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **Relay Chain**          | Polkadot                                                             | Kusama                                                               |
| **Parachain ID**         | 2034                                                                 | 2090                                                                 |
| **Genesis Hash**         | `0xafdc188f45c71dacbaa0b62e16a91f726c7b8699a9748cdf715459de6b7f366d` | `0xa85cfb9b9fd4d622a5b28289a02347af987d8f73fa3108450e2b4a11c1ce5755` |
| **Runtime (2025-10-01)** | specVersion `347`, transactionVersion `1`                            | specVersion `127`, transactionVersion `1`                            |
| **Unit Symbol**          | HDX                                                                  | BSX                                                                  |
| **Decimals**             | 12                                                                   | 12                                                                   |
| **SS58 Prefix**          | 63                                                                   | 10041                                                                |
| **Explorer**             | hydration.subscan.io                                                 | basilisk.subscan.io                                                  |

### Additional Details

| Parameter              | Value                                       | Details          |
| ---------------------- | ------------------------------------------- | ---------------- |
| Average Block Time     | 6 seconds                                   | GRANDPA finality |
| Native Liquidity Pools | Omnipool, LRNA staking, and routing pallets |                  |

## API Reference

Hydration exposes the full Substrate RPC surface for core operations, staking, governance, liquidity, and runtime-specific `state_call` helpers for omnipool pricing and router analytics.

## Common Integration Patterns

### Real-Time Block Streaming

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydration.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New Hydration block #${header.number.toString()} (${header.hash.toHex()})`);
});
```

### Query Treasury Balances via Raw Storage

```bash
curl https://api-hydration.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 42,
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b6a7c9a35a95a160cb4cad330558dfa56d6f646c755b98a7afd0913860592153322b957be394a0619f20b32679ac1014"
    ]
  }'
```

The key above targets `System.Account` for `5EYCAe5jiUusQ3yAkVAP1YF81oXasuAHt2KG8Xjc433Zbx8A` (Hydration treasury). Decode the SCALE response to obtain the 6,952,142,503,371.701702601733 HDX free balance observed on 2025-10-01.

### Batch Weight and Fee Simulation

```typescript
const api = await ApiPromise.create({ provider: new WsProvider('wss://api-hydration.n.dwellir.com/YOUR_API_KEY') });

const tx = api.tx.omnipool.sell(
  assetInId,
  assetOutId,
  amountIn,
  minimumReceived
);

const info = await api.rpc.payment.queryInfo(tx.toHex());
console.log(`Estimated fee: ${info.partialFee.toHuman()}`);
console.log(`Weight: ${info.weight.toString()} refTime`);
```

## Performance Best Practices

- Prefer WebSocket endpoints for subscriptions (`chain_subscribeNewHeads`, `grandpa_subscribeJustifications`).
- Cache runtime metadata and type registries keyed by `specVersion` (`347` as of 2025-10-01) to avoid repeated handshakes.
- Use `state_getKeysPaged` with `pageSize <= 1000` when scanning omnipool storage to prevent heavy RPC loads.
- Rate-limit bulk extrinsic submissions and enable exponential backoff on `author_submitExtrinsic` errors.
- Pin queries to finalized block hashes whenever you need deterministic historical data.

## Troubleshooting

| Symptom                          | Likely Cause                            | Resolution                                                               |
| -------------------------------- | --------------------------------------- | ------------------------------------------------------------------------ |
| `API key does not exist`         | Missing or mis-typed Dwellir key        | Re-issue credentials via the Dwellir dashboard and update endpoint URLs  |
| `1010: Invalid Transaction`      | Runtime version drift or outdated nonce | Re-fetch metadata, synchronize account nonce, and rebuild the payload    |
| Null `state_getStorage` response | Storage key mismatch                    | Recompute the key with `blake2_128_concat` of the SS58-decoded AccountId |
| WebSocket disconnects after idle | Inactive ping/pong                      | Enable keep-alive heartbeats every 20 seconds and auto-retry with jitter |

## FAQs

**Does Hydration support archive queries?**
Yes. Dwellir retains full historical state so you can request old block hashes, query omnipool states, and reconstruct trades for compliance.

**What SS58 prefix should wallets use?**
Hydration uses prefix `63`. Basilisk uses `10041`. Ensure address derivation matches the target environment.

**How do I estimate swap slippage programmatically?**
Fetch omnipool reserves via `state_call` (custom RPC `OmnipoolApi_quotePrice`) and pair it with `payment_queryInfo` estimates to account for weight-based fees.

## Smoke Tests

Run these checks before deploying to production:

1. **Node health**
   ```bash
   curl https://api-hydration.n.dwellir.com/YOUR_API_KEY \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}'
   ```
   Expect peers ≥ 8 and `isSyncing: false`.

2. **Latest header**
   ```bash
   curl https://api-hydration.n.dwellir.com/YOUR_API_KEY \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":2,"method":"chain_getHeader","params":[]}'
   ```
   Confirm block numbers advance roughly every 6 seconds.

3. **Account snapshot**
   ```bash
   curl https://api-hydration.n.dwellir.com/YOUR_API_KEY \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":3,"method":"state_getStorage","params":["0x26aa394eea5630e07c48ae0c9558cef7b6a7c9a35a95a160cb4cad330558dfa56d6f646c755b98a7afd0913860592153322b957be394a0619f20b32679ac1014"]}'
   ```
   Decode the SCALE payload and verify balances.

## Migration Guide (Polkadot → Hydration)

- **Update endpoints:** Replace legacy Polkadot URLs with `https://api-hydration.n.dwellir.com/YOUR_API_KEY` or the Basilisk staging endpoint.
- **Adjust address encoding:** Switch wallet and service configurations to SS58 prefix `63`. Existing Polkadot addresses (prefix `0`) must be re-derived.
- **Refresh metadata:** Download the latest metadata (`specVersion 347`) and update custom type bundles for omnipool-related pallets.
- **Re-evaluate fees:** Run `payment_queryInfo` against Hydration extrinsics. Weights differ from Polkadot because of liquidity logic.
- **Review pallet availability:** Hydration includes omnipool, router, and incentive pallets not present on Polkadot; ensure you check `rpc_methods` for the namespaces you rely on.

## Resources & Tools

- [Hydration node releases](https://github.com/galacticcouncil/HydraDX-node/releases): runtime changelogs and spec version history
- [Polkadot.js Apps explorer](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fapi-hydration.n.dwellir.com%2FYOUR_API_KEY#/explorer): browser-based console
- [Hydration runtime configuration source](https://github.com/galacticcouncil/hydration-node/blob/master/node/res/hydradx.json): chain specification in the node repository
- [Dwellir Dashboard](https://dashboard.dwellir.com/register): get your API key

Ready to launch? Deploy with Hydration's omnipool liquidity and monitor production traffic through Dwellir's analytics.

---

## author_pendingExtrinsics - Hydration RPC Method

# author_pendingExtrinsics - Hydration RPC Method

Returns all pending extrinsics currently in the transaction pool on Hydration. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`author_pendingExtrinsics` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Hydration
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Hydration transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/hydration/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/hydration/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/hydration/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Hydration RPC Method

# author_rotateKeys - Hydration RPC Method

Generate a new set of session keys on Hydration. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`author_rotateKeys` is critical for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Validator Setup** - Generate initial session keys when setting up a new validator on single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Hydration:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/hydration/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/hydration/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Hydration RPC Method

# author_submitAndWatchExtrinsic - Hydration RPC Method

Submits a signed extrinsic to Hydration and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Hydration
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-hydradx.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-hydradx.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-hydradx.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-hydradx.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/hydration/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/hydration/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/hydration/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/hydration/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Hydration RPC Method

# author_submitExtrinsic - Hydration RPC Method

Submits a fully signed extrinsic to Hydration for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`author_submitExtrinsic` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Token Transfers** -- Send native tokens or assets between accounts on Hydration
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-hydradx.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/hydration/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/hydration/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Hydration RPC Method

# beefy_getFinalizedHead - Hydration RPC Method

Returns the block hash of the latest BEEFY-finalized block on Hydration. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`beefy_getFinalizedHead` is important for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/hydration/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/hydration/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Hydration RPC Method

# chain_getBlock - Hydration RPC Method

Retrieves complete block information from Hydration, including the block header, extrinsics, and justifications.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/hydration/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/hydration/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/hydration/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Hydration RPC Method

# chain_getBlockHash - Hydration RPC Method

Returns the block hash for a given block number on Hydration. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`chain_getBlockHash` is fundamental for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Hydration
- **Block Navigation** - Navigate the blockchain history for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Hydration
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Hydration for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Hydration state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Hydration network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/hydration/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/hydration/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Hydration RPC Method

# chain_getFinalizedHead - Hydration RPC Method

Returns the hash of the last finalized block on Hydration. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`chain_getFinalizedHead` is critical for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Hydration
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-hydradx.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Hydration:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/hydration/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/hydration/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Hydration RPC Method

# chain_getHeader - Hydration RPC Method

Returns the block header for a given hash on Hydration. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`chain_getHeader` is ideal for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Hydration
- **Chain Synchronization** - Track block production and monitor chain progress for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Hydration:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Hydration chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Hydration block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/hydration/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Hydration RPC Method

# chain_subscribeFinalizedHeads - Hydration RPC Method

Subscribe to receive notifications when blocks are finalized on Hydration. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Exchange Deposits** - Only credit funds after finalization for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-hydradx.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-hydradx.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-hydradx.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Hydration:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/hydration/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/hydration/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Hydration RPC Method

# chain_subscribeNewHeads - Hydration RPC Method

Subscribe to receive notifications when new block headers are produced on Hydration. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`chain_subscribeNewHeads` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Block Monitoring** - Track new blocks in real time on Hydration for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-hydradx.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-hydradx.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-hydradx.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Hydration as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Hydration:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/hydration/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/hydration/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Hydration RPC Method

# grandpa_roundState - Hydration RPC Method

Returns the state of the current GRANDPA finality round on Hydration when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`grandpa_roundState` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Hydration, critical for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/hydration/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/hydration/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/hydration/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Hydration RPC Method

# payment_queryFeeDetails - Hydration RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Hydration. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`payment_queryFeeDetails` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Hydration
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/hydration/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/hydration/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/hydration/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/hydration/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Hydration RPC Method

# payment_queryInfo - Hydration RPC Method

Estimates the fee for an encoded extrinsic on Hydration. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`payment_queryInfo` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Hydration
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/hydration/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/hydration/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/hydration/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/hydration/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Hydration RPC Method

# rpc_methods - Hydration RPC Method

Returns a list of all RPC methods exposed by the Hydration node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`rpc_methods` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Hydration node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Hydration endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-hydradx.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Hydration endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/hydration/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/hydration/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Hydration RPC Method

# state_call - Hydration RPC Method

Calls a runtime API function on Hydration and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`state_call` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/hydration/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/hydration/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/hydration/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-hydration.n.dwellir.com/YOUR_API_KEY"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-hydration.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-hydration.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-hydration.n.dwellir.com/YOUR_API_KEY') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/hydration/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/hydration/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - Hydration RPC Method

# state_getKeysPaged - Hydration RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Hydration. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`state_getKeysPaged` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Hydration
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-hydradx.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/hydration/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/hydration/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Hydration RPC Method

# state_getMetadata - Hydration RPC Method

Returns the runtime metadata for Hydration as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`state_getMetadata` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Hydration
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Hydration:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Hydration:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/hydration/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/hydration/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Hydration RPC Method

# state_getRuntimeVersion - Hydration RPC Method

Returns the runtime version information for Hydration, including the spec name, spec version, implementation version, and supported API versions.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`state_getRuntimeVersion` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Hydration
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Hydration in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/hydration/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Hydration RPC Method

# state_getStorage - Hydration RPC Method

Returns the SCALE-encoded storage value for a given key on Hydration. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`state_getStorage` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Hydration
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/hydration/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/hydration/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Hydration RPC Method

# state_queryStorageAt - Hydration RPC Method

Queries multiple storage keys at a specific block on Hydration, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`state_queryStorageAt` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Hydration
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/hydration/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/hydration/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/hydration/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/hydration/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Hydration RPC Method

# system_chain - Hydration RPC Method

Returns the chain name of the Hydration network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`system_chain` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Network Verification** -- Confirm your application is connected to the correct Hydration network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Hydration"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-hydradx.dwellir.com/YOUR_API_KEY', 'Hydration');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/hydration/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/hydration/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/hydration/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/hydration/rpc_methods) -- List all available RPC methods

---

## system_health - Hydration RPC Method

# system_health - Hydration RPC Method

Returns the health status of the Hydration node, including peer count, sync state, and whether the node expects to have peers.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`system_health` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Hydration
- **Load Balancing** - Route requests only to healthy, fully synced nodes for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-hydradx.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-hydradx.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Hydration:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Hydration nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-hydradx.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/hydration/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Hydration RPC Method

# system_name - Hydration RPC Method

Returns the node implementation name on Hydration. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`system_name` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Hydration
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Hydration node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Hydration node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Hydration node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Hydration node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Hydration node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Hydration nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/hydration/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/hydration/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/hydration/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/hydration/rpc_methods) -- List all available RPC methods

---

## system_properties - Hydration RPC Method

# system_properties - Hydration RPC Method

Returns the chain-specific properties for Hydration, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`system_properties` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Hydration
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/hydration/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/hydration/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/hydration/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/hydration/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/hydration/rpc_methods) -- List all available RPC methods

---

## system_version - Hydration RPC Method

# system_version - Hydration RPC Method

Returns the node implementation version string on Hydration. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Hydration?** Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.

## When to Use This Method

`system_version` is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Hydration
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-hydradx.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-hydradx.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Hydration node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-hydradx.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Hydration node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-hydradx.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Hydration node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-hydradx.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Hydration node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-hydradx.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Hydration node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Hydration nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/hydration/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/hydration/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/hydration/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/hydration/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/hydration/rpc_methods) -- List all available RPC methods

---

## Hyperliquid API: gRPC, Order Book, Info and HyperEVM RPC

# Hyperliquid API: gRPC, Order Book, Info and HyperEVM RPC

## Hyperliquid plans and pricing

- **gRPC and Order Book:** $299/month for gRPC or $199/month for the Order Book, added to an API platform plan. Each streamed message costs 1 API credit.
- **Dedicated Node Cluster:** Starts at $4,000/month and 2 dedicated nodes. HyperEVM JSON-RPC, Info, gRPC and Order Book access are included, with no usage fees.

Details: [Hyperliquid pricing](https://www.dwellir.com/docs/hyperliquid/pricing) · [Shared plans](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication)

## Choose an access path

| Need                                            | Start with                                                      | Use it for                                                                                                |
| ----------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Stream node records or replay recent data       | [L1 gRPC Streaming API](https://www.dwellir.com/docs/hyperliquid/grpc)                 | Raw blocks, fills, statuses, book diffs, events, and TWAPs, with V3 server-side filtering where supported |
| Consume live L2/L4 books and trades             | [Order Book WebSocket API](https://www.dwellir.com/docs/hyperliquid/order-book-server) | Purpose-built order books and trade streams                                                               |
| Query indexed candles, fills, orders, and TWAPs | [Hyperliquid Index](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index)        | Queryable historical market and account data                                                              |
| Download node files and long-range raw data     | [Archival data](https://www.dwellir.com/docs/hyperliquid/historical-data)              | S3 Bucket files for research, replay, and backtesting                                                     |
| Query current market and user state             | [HyperCore Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint)      | HTTP request-response queries for metadata, positions, vaults, and exchange state                         |
| Keep your own node peered and in sync           | [Hyperliquid Peering](https://www.dwellir.com/docs/hyperliquid/peering)                | Reserved gossip peer slots with full mempool and a 99.9% uptime SLA                                       |

## How Hyperliquid works

For endpoint selection, symbols, quiet streams, replay, reconnects, freshness, and peering, see [streaming troubleshooting](https://www.dwellir.com/docs/hyperliquid/troubleshooting).

For the protocol-level picture, including HyperBFT consensus, HyperCore, HyperEVM, API servers, nodes, and public rate limits, see [How Hyperliquid's infrastructure works](https://www.dwellir.com/docs/hyperliquid/architecture).

Hyperliquid nodes write raw protocol records to disk. Dwellir exposes available raw feeds through [gRPC](https://www.dwellir.com/docs/hyperliquid/grpc), while the [historical archive](https://www.dwellir.com/docs/hyperliquid/historical-data) preserves native files for longer-term workflows.

### Data written by the node

| Node source                                                                                | Purpose                                                                       | Live access                                                                                                                                       | Archival data                                                                                                                                                                   |
| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`replica_cmds`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks)                         | Hyperliquid blocks, signed actions, responses, and consensus metadata         | [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks), [GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block)                                                          | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2025-01-25` to today                                                                                                       |
| [`node_fills_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                   | Per-account execution records grouped by sequential block number              | [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills), [GetFills](https://www.dwellir.com/docs/hyperliquid/get_fills), [hl\_getBatchBlocks](https://www.dwellir.com/docs/hyperliquid/hl_getBatchBlocks) | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2025-07-27` to today; [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data); [indexed fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills) |
| [`node_order_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/order-statuses) | Order lifecycle events, including opens, fills, cancellations, and rejections | [StreamOrderStatuses](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses), [GetOrderStatuses](https://www.dwellir.com/docs/hyperliquid/get_order_statuses)                          | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-01-22` to today; [indexed order history](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/historical-orders)                 |
| [`node_raw_book_diffs_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/book-diffs)     | Native order-level additions, updates, and removals                           | [StreamRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs), [GetRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/get_raw_book_diffs)                            | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-01-22` to today                                                                                                       |
| [`misc_events_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/misc-events)            | Miscellaneous protocol events                                                 | [StreamMiscEvents](https://www.dwellir.com/docs/hyperliquid/stream_misc_events), [GetMiscEvents](https://www.dwellir.com/docs/hyperliquid/get_misc_events)                                      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-06-29` to today                                                                                                       |
| [`node_twap_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/twap-statuses)   | TWAP lifecycle events                                                         | [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses), [GetTwapStatuses](https://www.dwellir.com/docs/hyperliquid/get_twap_statuses)                              | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-07-01` to today                                                                                                       |
| [`periodic_abci_states`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/abci-states)            | Periodic RMP state dumps that can seed generated order-book snapshots         | [Dedicated Node Cluster gRPC](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster)                                                                        | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-04-14` to today                                                                                                       |

The node can also write `mempool_txs`: pre-consensus client blocks with signed transaction requests that are not guaranteed to land in a block. They are available live through [StreamMempoolTxs](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs) and [GetMempoolTxs](https://www.dwellir.com/docs/hyperliquid/get_mempool_txs) where the endpoint serves the feed, and are not part of the S3 Bucket.

### Order books and derived data

V3 market streams expose typed live views without backfill. Use Archival data or indexed history when you need historical coverage.

| Derived view                                                                            | V3 market method                                                                                                                            | Related live or indexed access                                                                       |
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [L2 book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l2-book)                     | [StreamL2Book](https://www.dwellir.com/docs/hyperliquid/stream_l2_book)                                                                                            | [Order Book WebSocket L2](https://www.dwellir.com/docs/hyperliquid/l2-book)                                                 |
| [Best bid and offer](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/bbo)                        | [StreamBbo](https://www.dwellir.com/docs/hyperliquid/stream_bbo)                                                                                                   | [Order Book WebSocket BBO](https://www.dwellir.com/docs/hyperliquid/bbo)                                                    |
| [Ordered L2 book changes](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l2-book)               | [StreamL2BookDiff](https://www.dwellir.com/docs/hyperliquid/stream_l2_book_diff)                                                                                   | Seed from a known snapshot before applying diffs                                                     |
| [Full L4 order book](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book)                    | [StreamL4Book](https://www.dwellir.com/docs/hyperliquid/stream_l4_book)                                                                                            | [Order Book WebSocket L4](https://www.dwellir.com/docs/hyperliquid/l4-book)                                                 |
| [Typed L4 order updates](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book)                | [StreamL4OrderUpdates](https://www.dwellir.com/docs/hyperliquid/stream_l4_order_updates)                                                                           | [Order Book WebSocket overview](https://www.dwellir.com/docs/hyperliquid/order-book-server)                                 |
| Take-profit and stop-loss updates                                                       | [StreamTpslUpdates](https://www.dwellir.com/docs/hyperliquid/stream_tpsl_updates)                                                                                  | [Order Book WebSocket overview](https://www.dwellir.com/docs/hyperliquid/order-book-server)                                 |
| [Matched trades](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/trades)                         | [StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades)                                                                                             | [Order Book WebSocket trades](https://www.dwellir.com/docs/hyperliquid/trades) and [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data) |
| [All account fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)                  | [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills)                                                                                        | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/all-fills)                       |
| [Fills for one user](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)                 | [StreamUserFills](https://www.dwellir.com/docs/hyperliquid/stream_user_fills)                                                                                      | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                 |
| [Builder-attributed fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)           | [StreamBuilderFills](https://www.dwellir.com/docs/hyperliquid/stream_builder_fills)                                                                                | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                 |
| [Liquidation fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)                  | [StreamLiquidationFills](https://www.dwellir.com/docs/hyperliquid/stream_liquidation_fills)                                                                        | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                 |
| [Live candles](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/candles)                          | [StreamCandle](https://www.dwellir.com/docs/hyperliquid/stream_candle)                                                                                             | Indexed [OHLCV history](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data)                              |
| [Generated order-book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots) | [StreamOrderbookSnapshots](https://www.dwellir.com/docs/hyperliquid/stream_orderbook_snapshots), [GetOrderbookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot) | [Order Book WebSocket L4](https://www.dwellir.com/docs/hyperliquid/l4-book)                                                 |
| [All market mids](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/market-context)                | [StreamAllMids](https://www.dwellir.com/docs/hyperliquid/stream_all_mids)                                                                                          | [Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint)                                                     |
| [Active asset context](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/market-context)           | [StreamActiveAssetCtx](https://www.dwellir.com/docs/hyperliquid/stream_active_asset_ctx)                                                                           | [Active asset data](https://www.dwellir.com/docs/hyperliquid/active-asset-data)                                             |

Order-book reconstruction requires a snapshot or another known state seed followed by ordered diffs. Raw diffs alone are insufficient. For trades, a match can contain multiple makers. Within one block, group fills by `(coin, tid)`. Across blocks, include `block_number` or `block_time` because `tid` is not globally unique.

## Why Build on Hyperliquid?

Hyperliquid is a high-performance Layer 1 blockchain purpose-built for decentralized trading, offering both EVM compatibility through HyperEVM and specialized L1 features through gRPC streaming.

### **Blazing Fast Performance**

- **Sub-second finality** - Near-instant transaction confirmations
- **200,000 orders/second** - Unprecedented throughput for DeFi
- **Predictable low fees** - Stable and minimal transaction costs

### **Dual API Architecture**

- **HyperEVM** - Full EVM compatibility for Solidity smart contracts
- **L1 gRPC Streaming** - Real-time order books and market data
- **Native Trading Primitives** - Built-in support for spot and perpetuals

### **Trading-Optimized Infrastructure**

- **Fully on-chain order books** - No off-chain components
- **HyperBFT consensus** - Optimized for trading performance
- **Real-time market data** - Stream fills, trades, and order updates

## Quick Start with Hyperliquid

### Pricing and access

Dwellir provides HyperEVM JSON-RPC and HyperCore trading data, including Info, gRPC, and Order Book endpoints. An EVM RPC endpoint alone does not include HyperCore market streams.

On the shared cluster, add gRPC ($299/month) or Order Book ($199/month) access to an [API plan](https://www.dwellir.com/docs/hyperliquid/pricing). Both add-ons are metered: each streamed message costs 1 API credit.

A [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster) starts at $4,000/month and 2 dedicated backend nodes. HyperEVM JSON-RPC, Info, gRPC, and Order Book access are included and unmetered. There are no separate gRPC or Order Book add-on fees. See [when to upgrade to a Dedicated Node Cluster](https://www.dwellir.com/blog/hyperliquid-dedicated-node-clusters).

HyperEVM JSON-RPC is sold through the Dwellir API platform on the same plans as every other network, billed at 1 API credit per response. Create an API key in the [dashboard](https://dashboard.dwellir.com/register) and use the HyperEVM endpoint:

### Installation & Setup

Ethers.js (HyperEVM)
gRPC (V3)

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to HyperEVM (chain ID 999)
const provider = new JsonRpcProvider(
  'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'
);

// Deploy and interact with Solidity contracts
const contract = new Contract(address, abi, provider);
const result = await contract.someMethod();
```

```go
import (
    "context"
    "crypto/tls"
    "fmt"
    "log"
    "os"
    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

// Connect to L1 Gateway for streaming
creds := credentials.NewTLS(&tls.Config{})
conn, err := grpc.Dial(
    "YOUR_DEDICATED_NODE.hyperliquid.dwellir.com:443",
    grpc.WithTransportCredentials(creds),
)
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := pb.NewHyperliquidL1GatewayClient(conn)

// Get the latest generated order-book snapshot with V3.
ctx := metadata.AppendToOutgoingContext(
    context.Background(),
    "x-api-key", os.Getenv("DWELLIR_API_KEY"),
)
var response *pb.Record
response, err = client.GetOrderbookSnapshot(
    ctx,
    &pb.GetRequest{},
)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(response.Data))
```

## Network Information

| Parameter  | Value      | Details             |
| ---------- | ---------- | ------------------- |
| Chain ID   | 999        | Mainnet             |
| Block Time | < 1 second | Sub-second finality |
| Gas Token  | HYPE       | Native token        |
| Consensus  | HyperBFT   | Trading-optimized   |

## API Reference

## HyperEVM JSON-RPC API

HyperEVM provides full Ethereum compatibility, supporting all standard JSON-RPC methods for smart contract deployment and interaction.

### EVM Integration Examples

Deploy Contracts
Query Data

```solidity
// Deploy custom trading logic on HyperEVM
contract TradingStrategy {
    function executeTrade(
        address tokenA,
        address tokenB,
        uint256 amount
    ) external {
        // Your trading logic here
        // Access Hyperliquid's native features
    }
}
```

```javascript
// Read contract state and market data
const provider = new JsonRpcProvider(HYPERLIQUID_RPC);

// Get current block with trading data
const block = await provider.getBlock('latest');
console.log('Block trades:', block.transactions);

// Query contract for positions
const positions = await contract.getPositions(trader);
```

## Order Book WebSocket API

Access real-time L2 and L4 order-book data through the Order Book WebSocket API:

## L1 gRPC Streaming API

Access Hyperliquid's native Layer 1 features through our specialized gRPC interface:

### Available gRPC Streams

- **Order Book Snapshots** - Generated snapshots through the snapshot RPCs
- **Block Streaming** - Real-time block updates
- **Trade Streams** - Live trade execution data
- **Fill Streams** - Order fill notifications

### Quick gRPC Example (V3)

Go (V3)
Python (V3)

```go
import (
    "context"
    "crypto/tls"
    "fmt"
    "log"
    "os"
    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

// Connect to L1 Gateway for streaming
creds := credentials.NewTLS(&tls.Config{})
conn, err := grpc.Dial(
    "YOUR_DEDICATED_NODE.hyperliquid.dwellir.com:443",
    grpc.WithTransportCredentials(creds),
)
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := pb.NewHyperliquidL1GatewayClient(conn)

// Get the latest generated order-book snapshot with V3.
ctx := metadata.AppendToOutgoingContext(
    context.Background(),
    "x-api-key", os.Getenv("DWELLIR_API_KEY"),
)
var response *pb.Record
response, err = client.GetOrderbookSnapshot(
    ctx,
    &pb.GetRequest{},
)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(response.Data))
```

```python
import json
import os
import grpc
from v3_pb2 import GetRequest, Record
from v3_pb2_grpc import HyperliquidL1GatewayStub

# Create gRPC channel
channel = grpc.secure_channel(
    'YOUR_DEDICATED_NODE.hyperliquid.dwellir.com:443',
    grpc.ssl_channel_credentials()
)
stub = HyperliquidL1GatewayStub(channel)
metadata = [('x-api-key', os.environ['DWELLIR_API_KEY'])]

# Get the latest generated order-book snapshot with V3.
try:
    response: Record = stub.GetOrderbookSnapshot(GetRequest(), metadata=metadata)
    data = json.loads(response.data)
    print(f"Order book snapshot: {data}")
except grpc.RpcError as error:
    raise RuntimeError(f"gRPC request failed: {error.details()}") from error
```

## Common Integration Patterns

### **Algorithmic Trading**

Combine HyperEVM smart contracts with L1 streaming for sophisticated trading:

```javascript
// Deploy strategy contract via HyperEVM
const strategy = await deployContract(strategyABI, strategyBytecode);

// Stream blocks via gRPC for trading data
const blockStream = grpcClient.StreamBlocks();
blockStream.on('data', async (block) => {
  const signal = analyzeBlockData(block);
  if (signal.shouldTrade) {
    await strategy.executeTrade(signal.params);
  }
});
```

### **Market Making**

Provide liquidity using real-time data:

```python
# Monitor block data via gRPC
for block in stub.StreamBlocks(timestamp):
    data = analyze_block(block)
    if data.spread > target_spread:
        # Place orders via HyperEVM
        place_limit_orders(provider, spread)
```

### **DeFi Composability**

Build complex DeFi applications:

```solidity
// Leverage Hyperliquid's native features
contract YieldVault {
    function harvestAndCompound() external {
        // Access perpetuals for hedging
        // Use spot for liquidity
        // Compound yields automatically
    }
}
```

## Use Cases

### **Perpetuals Trading**

Leverage Hyperliquid's native perpetuals with up to 40x leverage (BTC), fully on-chain order books, and sub-second execution.

### **Spot Trading**

Access deep liquidity for spot markets with minimal slippage and predictable fees.

### **Market Making**

Provide liquidity using HyperEVM smart contracts combined with L1 streaming for optimal spreads.

### **Cross-Chain Arbitrage**

Build bridges and arbitrage bots leveraging Hyperliquid's speed advantage over other chains.

## Agent Skill

The [Hyperliquid agent skill](https://github.com/dwellir-public/hyperliquid-skills) gives AI coding agents procedural knowledge for building on Hyperliquid through Dwellir's infrastructure. It follows the open [Agent Skills standard](https://skills.sh), making it portable across 40+ AI coding agents including Claude Code, Cursor, and Windsurf.

Install it with a single command:

```bash
npx skills add dwellir-public/hyperliquid-skills
```

Once installed, the skill automatically activates when your agent encounters Hyperliquid-related tasks. It covers HyperEVM JSON-RPC, the Info API, gRPC streaming, order book WebSocket access, and native API routing for order placement.

- [View on Skills.sh](https://skills.sh/dwellir-public/hyperliquid-skills/hyperliquid)
- [GitHub repository](https://github.com/dwellir-public/hyperliquid-skills)

## Resources & Support

### Developer Resources

- **HyperEVM JSON-RPC** - Full Ethereum-compatible RPC interface
- [L1 gRPC API Reference](https://www.dwellir.com/docs/hyperliquid/grpc) - Streaming API documentation
- [**V2 and V3 proto contracts**](https://www.dwellir.com/docs/hyperliquid/grpc#versions-and-services) - Checked-in service definitions and version guidance
- **Testing Tools** - 16MB Go binary for stream verification

### API Access

- [gRPC and Order Book add-ons](https://www.dwellir.com/docs/hyperliquid/pricing): $299/month and $199/month on any API plan, metered per streamed message
- [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster): from $4,000/month with gRPC and Order Book add-ons included
- **Custom Endpoints** - Isolated infrastructure for your application
- **Uncapped Throughput** - No rate limits on dedicated node clusters

### Need Help?

- **Email**: <support@dwellir.com>
- **HyperEVM Docs**: Standard Ethereum JSON-RPC methods
- **L1 Streaming**: [gRPC API Reference](https://www.dwellir.com/docs/hyperliquid/grpc)
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Build on Hyperliquid with Dwellir: HyperEVM JSON-RPC on the standard API plans, L1 streaming add-ons, or a Dedicated Node Cluster. [Create an API key](https://dashboard.dwellir.com/register)*

---

## activeAssetData - HyperCore Info Endpoint

# activeAssetData - HyperCore Info Endpoint

Get active asset trading data for a specific user and coin, including leverage configuration, maximum trade sizes, available trading amounts, and current mark price.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `activeAssetData` endpoint is essential for:

- **Pre-Trade Validation** — Check maximum trade sizes before placing orders
- **Leverage Monitoring** — Query current leverage settings for a user on a specific asset
- **Available Capital** — Determine how much a user can trade on a given asset
- **Price Reference** — Get the current mark price for position calculations

## Request Parameters

- `type` (`string, required`): parameter: Must be `"activeAssetData"`
- `user` (`string, required`): parameter: User's Ethereum wallet address
- `coin` (`string, required`): parameter: Asset symbol (e.g., `"BTC"`, `"ETH"`)

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "activeAssetData",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f",
  "coin": "BTC"
}'
```

## Response Fields

- `user` (`string, required`): The queried Ethereum address
- `coin` (`string, required`): The queried asset symbol
- `leverage` (`object, required`): Current leverage configuration
- `maxTradeSzs` (`array, required`): Maximum trade sizes [long, short] as strings
- `availableToTrade` (`array, required`): Available trading amounts [long, short] as strings
- `markPx` (`string, required`): Current mark price for the asset

## Successful Response

```json
{
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f",
  "coin": "BTC",
  "leverage": {
    "type": "cross",
    "value": 5,
    "rawUsd": null
  },
  "maxTradeSzs": ["100000.00", "100000.00"],
  "availableToTrade": ["50000.00", "50000.00"],
  "markPx": "45000.00"
}
```

## Common Use Cases

### 1. Pre-Trade Size Validation

Validate order size before submitting:

```javascript
async function validateTradeSize(userAddress, coin, desiredSize, side) {
  const data = await getActiveAssetData(userAddress, coin);

  const sideIndex = side === 'long' ? 0 : 1;
  const maxSize = parseFloat(data.maxTradeSzs[sideIndex]);
  const available = parseFloat(data.availableToTrade[sideIndex]);

  const isValid = desiredSize <= maxSize && desiredSize <= available;

  return {
    valid: isValid,
    desiredSize: desiredSize,
    maxTradeSize: maxSize,
    availableToTrade: available,
    reason: !isValid
      ? desiredSize > maxSize
        ? `Exceeds max trade size ($${maxSize})`
        : `Exceeds available capital ($${available})`
      : null
  };
}

// Usage
const validation = await validateTradeSize(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  'BTC',
  25000,
  'long'
);

if (!validation.valid) {
  console.warn(`Trade rejected: ${validation.reason}`);
}
```

### 2. Leverage Dashboard

Display leverage and trading capacity for multiple assets:

```javascript
async function getLeverageDashboard(userAddress, coins) {
  const results = await Promise.all(
    coins.map(coin => getActiveAssetData(userAddress, coin))
  );

  console.log('=== Leverage Dashboard ===\n');
  results.forEach(data => {
    console.log(`${data.coin}:`);
    console.log(`  Leverage: ${data.leverage.value}x (${data.leverage.type})`);
    console.log(`  Mark Price: $${data.markPx}`);
    console.log(`  Max Long: $${data.maxTradeSzs[0]}`);
    console.log(`  Max Short: $${data.maxTradeSzs[1]}`);
    console.log(`  Available Long: $${data.availableToTrade[0]}`);
    console.log(`  Available Short: $${data.availableToTrade[1]}`);
    console.log('');
  });

  return results;
}

// Usage
await getLeverageDashboard(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  ['BTC', 'ETH', 'SOL']
);
```

### 3. Trading Capacity Monitor

Track available trading capacity over time:

```javascript
class TradingCapacityMonitor {
  constructor(userAddress, coin) {
    this.userAddress = userAddress;
    this.coin = coin;
    this.history = [];
  }

  async snapshot() {
    const data = await getActiveAssetData(this.userAddress, this.coin);

    const record = {
      timestamp: new Date().toISOString(),
      availableLong: parseFloat(data.availableToTrade[0]),
      availableShort: parseFloat(data.availableToTrade[1]),
      markPx: parseFloat(data.markPx),
      leverage: data.leverage.value
    };

    this.history.push(record);
    return record;
  }

  getUtilization() {
    if (this.history.length === 0) return null;

    const latest = this.history[this.history.length - 1];
    const first = this.history[0];

    return {
      currentAvailableLong: latest.availableLong,
      currentAvailableShort: latest.availableShort,
      changeLong: latest.availableLong - first.availableLong,
      changeShort: latest.availableShort - first.availableShort,
      snapshots: this.history.length
    };
  }
}

// Usage
const monitor = new TradingCapacityMonitor(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  'BTC'
);
await monitor.snapshot();
```

### 4. Smart Order Sizing

Calculate optimal order size based on available capacity:

```javascript
async function getOptimalOrderSize(userAddress, coin, side, targetPercent = 0.5) {
  const data = await getActiveAssetData(userAddress, coin);

  const sideIndex = side === 'long' ? 0 : 1;
  const available = parseFloat(data.availableToTrade[sideIndex]);
  const maxSize = parseFloat(data.maxTradeSzs[sideIndex]);
  const markPrice = parseFloat(data.markPx);

  const targetNotional = available * targetPercent;
  const clampedNotional = Math.min(targetNotional, maxSize);
  const orderSizeInCoin = clampedNotional / markPrice;

  return {
    coin: coin,
    side: side,
    orderSizeUsd: clampedNotional.toFixed(2),
    orderSizeCoin: orderSizeInCoin.toFixed(6),
    markPrice: markPrice,
    leverage: data.leverage.value,
    percentUsed: ((clampedNotional / available) * 100).toFixed(1)
  };
}

// Usage
const order = await getOptimalOrderSize(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  'BTC',
  'long',
  0.25 // use 25% of available capital
);
console.log(`Order: ${order.orderSizeCoin} ${order.coin} ($${order.orderSizeUsd})`);
```

## Best Practices

1. **Query before trading** — Always check available trade sizes before placing orders
2. **Cache mark prices briefly** — Mark prices change frequently, cache for seconds not minutes
3. **Validate coin symbols** — Use the [meta](https://www.dwellir.com/docs/hyperliquid/meta) endpoint to get valid coin symbols
4. **Handle both sides** — `maxTradeSzs` and `availableToTrade` arrays contain \[long, short] values
5. **Monitor leverage changes** — Leverage mode affects available capital calculations

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get full account state with all positions
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata and valid coin symbols
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get user's open orders for the asset
- [**userAbstraction**](https://www.dwellir.com/docs/hyperliquid/user-abstraction) — Check account abstraction mode

***

*Query real-time trading capacity with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## agentEnableDexAbstraction payload - Agent DEX Settings

# agentEnableDexAbstraction payload - Agent DEX Settings

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `agentEnableDexAbstraction` payload records a request to enable DEX abstraction for an agent wallet.

## Sample Data

```json
{
  "signature": {
    "r": "0x2d58053666731bbc738cb5bafd19bb148a85248b19565bf72ab22599a00eaf51",
    "s": "0x1b7aae8cfa48af734057d0f886fd8b14b2d4a3e53df388f30901934ad3552453",
    "v": 28
  },
  "action": {
    "type": "agentEnableDexAbstraction"
  },
  "nonce": 1768146926373
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xd11ddee9a7be6badd297043326457f02015000cf42b18a7f74e68a3c66b24598)

## Field Reference

### Action Fields

| Field  | Type   | Description                          |
| ------ | ------ | ------------------------------------ |
| `type` | string | Always `"agentEnableDexAbstraction"` |

## Use Cases

### DEX Abstraction Tracking

Monitor DEX abstraction enablement:

```python
def process_agentEnableDexAbstraction_action(action):
    print("DEX abstraction enabled for agent")
```

## Related Action Payloads

- [approveAgent](https://www.dwellir.com/docs/hyperliquid/approveAgent) - Agent authorization
- [userDexAbstraction](https://www.dwellir.com/docs/hyperliquid/userDexAbstraction) - User DEX settings

---

## approveAgent payload - API Wallet Authorization

# approveAgent payload - API Wallet Authorization

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `approveAgent` payload records authorization for an API wallet, also called an agent, to sign on behalf of a master account or its sub-accounts.

## Sample Data

```json
{
  "signature": {
    "r": "0xa440cd8904dfbd812cb3669258413c6139c12dbc7083ea000b1f73e4ff4ef1e3",
    "s": "0x79c77f830c666018af5e13d229d8955e1e4f7fe89e225886cd9b8f638c2d8638",
    "v": 28
  },
  "action": {
    "type": "approveAgent",
    "signatureChainId": "0x2105",
    "hyperliquidChain": "Mainnet",
    "agentAddress": "0x9c0e10bb3ac3b461b2a24c4465ece3f343d6321a",
    "agentName": "DEFI_AGENT_3 valid_until 1768319711089",
    "nonce": 1768146911127
  },
  "nonce": 1768146911127
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xe21c188afbddc331e39504332644bf0201a2007096d0e20385e4c3ddbad19d1c)

## Field Reference

### Action Fields

| Field              | Type   | Description                                                  |
| ------------------ | ------ | ------------------------------------------------------------ |
| `type`             | string | Always `"approveAgent"`                                      |
| `signatureChainId` | string | Chain ID for EIP-712 signing (e.g., `"0xa4b1"` for Arbitrum) |
| `hyperliquidChain` | string | Target chain: `"Mainnet"` or `"Testnet"`                     |
| `agentAddress`     | string | Ethereum address of the agent wallet to authorize            |
| `agentName`        | string | Optional human-readable name for the agent                   |
| `nonce`            | number | Timestamp-based nonce for replay protection                  |

## Agent Naming

Agents can be named or unnamed:

- **Named agents**: Identified by `agentName`. Sending a new `approveAgent` with the same name replaces the previous agent.
- **Unnamed agents**: No name specified. Only one unnamed agent can exist at a time.

Common agent names include wallet integrations like `"rabby-mobile"`, `"metamask"`, or custom names for trading bots.

## Security Considerations

- Agent wallets can only sign trading operations, not withdrawals
- The master wallet must sign `approveAgent` actions directly
- Once deregistered, an agent's nonce state may be pruned, potentially allowing replay of old signed actions
- Generate new agent wallets rather than reusing addresses

## Use Cases

### Trading Bot Setup Detection

Monitor when new trading bots or API integrations are authorized:

```python
def process_approveAgent_action(action):
    agent_address = action.get('agentAddress')
    agent_name = action.get('agentName', 'unnamed')

    print(f"Agent authorized: {agent_name} ({agent_address})")
```

### Wallet Integration Tracking

Track adoption of different wallet providers by monitoring agent names.

### Security Monitoring

Detect unauthorized agent approvals for accounts you're monitoring.

## Related Action Payloads

- [approveBuilderFee](https://www.dwellir.com/docs/hyperliquid/approveBuilderFee) - Builder fee approvals
- [agentEnableDexAbstraction](https://www.dwellir.com/docs/hyperliquid/agentEnableDexAbstraction) - Agent DEX abstraction settings

---

## approveBuilderFee payload - Builder Fee Approval

# approveBuilderFee payload - Builder Fee Approval

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `approveBuilderFee` payload records the maximum fee rate a user authorizes a builder to charge on routed trades.

## Sample Data

```json
{
  "signature": {
    "r": "0x819ad144d5c0c3d55a176f1b61ee61f2ad290f1b4cc2afb3944c2f70235a507d",
    "s": "0x2fea989745633804f70c5528c9258a89b3789bd99c6a03c6a1bd884cf5dc1b6b",
    "v": 28
  },
  "action": {
    "type": "approveBuilderFee",
    "signatureChainId": "0x66eee",
    "hyperliquidChain": "Mainnet",
    "maxFeeRate": "0.01%",
    "builder": "0x6530512a6c89c7cfcebc3ba7fcd9ada5f30827a6",
    "nonce": 1768146914155
  },
  "nonce": 1768146914155
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xb044c574237def57b1be04332644d00202170059be710e29540d70c6e271c942)

## Field Reference

### Action Fields

| Field        | Type   | Description                                                      |
| ------------ | ------ | ---------------------------------------------------------------- |
| `type`       | string | Always `"approveBuilderFee"`                                     |
| `maxFeeRate` | string | Maximum fee rate the builder can charge (e.g., `"0.001"` = 0.1%) |
| `builder`    | string | Ethereum address of the builder                                  |
| `nonce`      | number | Timestamp-based nonce for replay protection                      |

## Fee Limits

Hyperliquid enforces maximum builder fees:

| Market Type | Maximum Builder Fee    |
| ----------- | ---------------------- |
| Perpetuals  | 0.1% (10 basis points) |
| Spot        | 1% (100 basis points)  |

Builder codes do not apply to the buying side of spot trades.

## How Builder Fees Work

1. User approves a max fee rate for a builder address
2. Builder submits orders with a fee parameter: `{"b": address, "f": fee_bps}`
3. Fee is deducted from the user's trade and credited to the builder
4. Builders claim fees through the referral reward system

## Use Cases

### DeFi Integration Tracking

Monitor which builders users are authorizing:

```python
def process_approveBuilderFee_action(action):
    builder = action.get('builder')
    max_fee = float(action.get('maxFeeRate', 0))

    print(f"Builder approved: {builder} with max fee {max_fee * 100}%")
```

### Fee Analytics

Track builder fee approvals to understand:

- Popular trading interfaces
- Average fee tolerance
- Builder market share

### Competition Analysis

Monitor which builders are gaining traction in the Hyperliquid ecosystem.

## Requirements

- Builder must maintain at least 100 USDC in perps account value
- Approval must be signed by the user's main wallet (not an agent)
- Users can revoke permissions at any time

## Related Action Payloads

- [approveAgent](https://www.dwellir.com/docs/hyperliquid/approveAgent) - API wallet authorization
- [order](https://www.dwellir.com/docs/hyperliquid/order) - Orders can include builder fee parameters

---

## How Hyperliquid's Infrastructure Works

# How Hyperliquid's Infrastructure Works

Hyperliquid is a Layer 1 blockchain built around a custom consensus protocol called HyperBFT. The chain has one state, split into two execution environments that HyperBFT secures together: HyperCore, the native trading engine, and HyperEVM, a general-purpose EVM. Neither layer is a separate chain, and there is no bridge between them. API clients never talk to validators directly. Reads and writes go through Hyperliquid's API servers, or through a non-validating node you run yourself.

This page describes each layer, what it exposes, and where the public endpoints stop being enough for production workloads.

![Hyperliquid execution layers above shared HyperBFT consensus](https://www.dwellir.com/img/hyperliquid/hyperliquid_execution_layers.webp)

HyperCore and HyperEVM side by side, each connected by an arrow to the HyperBFT consensus layer beneath them. Read precompiles and CoreWriter link the two layers. A One State label sits between the connectors. HyperCore: 200k orders per second, gas-free trading. HyperEVM: 1 second small blocks with 3M gas, 1 minute big blocks with 30M gas, chain ID 999. HyperBFT: 0.2 s median and 0.9 s 99th percentile end-to-end latency.

## What consensus does Hyperliquid use?

Hyperliquid uses HyperBFT, a variant of HotStuff consensus. It is proof of stake: validators produce blocks in proportion to the HYPE staked to them. Every committed block is final. There is no probabilistic finality and no reorg window to handle in client code.

HyperBFT is the one thing both execution layers share. HyperCore and HyperEVM state live in the same blocks, ordered by the same validators, so a HyperCore fill and a HyperEVM contract call that land in the same block are final together. Hyperliquid is one state secured by one consensus.

| Measure                                               | Value                           | Source                                                                                 |
| ----------------------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------- |
| Median end-to-end latency, co-located client          | 0.2 seconds                     | [Hyperliquid docs](https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/overview) |
| 99th percentile end-to-end latency, co-located client | 0.9 seconds                     | [Hyperliquid docs](https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/overview) |
| Mainnet throughput                                    | About 200,000 orders per second | [Hyperliquid docs](https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/overview) |

End-to-end latency here means the time from sending a request to receiving the committed execution response. The current bottleneck is execution, not consensus or networking.

## What is HyperCore?

HyperCore is the native execution environment. It holds the perpetual and spot order books, the clearinghouse that tracks margin, positions, and funding, the oracle, staking, and vaults. Every order, cancel, trade, and liquidation is on-chain and ordered by HyperBFT. There is no off-chain matching engine.

HyperCore is not an EVM. You cannot read the order book with `eth_call` or place an order from a Solidity contract directly. It has its own API surface:

| Surface           | Public endpoint                             | What it does                                      |
| ----------------- | ------------------------------------------- | ------------------------------------------------- |
| Info endpoint     | `POST https://api.hyperliquid.xyz/info`     | Read market data, metadata, and account state     |
| Exchange endpoint | `POST https://api.hyperliquid.xyz/exchange` | Submit signed actions: orders, cancels, transfers |
| WebSocket         | `wss://api.hyperliquid.xyz/ws`              | Stream trades, books, fills, and account updates  |

Trading on HyperCore is gas-free. Users pay trading fees on filled volume and nothing per order or cancel.

Two other costs apply. Each address has a request budget for exchange actions. It starts with a buffer of 10,000 requests, earns one more request per 1 USDC traded, and can reserve extra actions at 0.0005 USDC each. New accounts also pay a one-time activation fee of 1 quote token on their first inbound transfer.

## What is HyperEVM?

HyperEVM is a general-purpose EVM that runs as part of the same Hyperliquid execution, under the same HyperBFT consensus. It is not a separate chain or a rollup. HyperEVM blocks are built inside the same L1 execution as HyperCore, which is why contracts on HyperEVM can read HyperCore state with no bridging. Hyperliquid's docs put it directly: the HyperEVM "is not a separate chain, but rather, secured by the same HyperBFT consensus as HyperCore."

| Property         | Value                                                      |
| ---------------- | ---------------------------------------------------------- |
| Mainnet chain ID | 999                                                        |
| Testnet chain ID | 998                                                        |
| Gas token        | HYPE, 18 decimals                                          |
| EVM version      | Cancun, without blobs                                      |
| Fee model        | EIP-1559. Base fees and priority fees are both burned      |
| Official RPC     | `https://rpc.hyperliquid.xyz/evm`, HTTP only, no WebSocket |

### Dual-block architecture

HyperEVM throughput is split between two block types that interleave in one increasing sequence of EVM block numbers:

| Block type  | Cadence        | Gas limit | Use                                    |
| ----------- | -------------- | --------- | -------------------------------------- |
| Small block | Every 1 second | 3M gas    | Normal transactions, fast confirmation |
| Big block   | Every 1 minute | 30M gas   | Large contract deployments             |

Transactions go to small blocks by default. To target big blocks, the sender submits the HyperCore action `evmUserModify` with `usingBigBlocks: true`, and can use the `bigBlockGasPrice` JSON-RPC method to estimate the next big block's base fee. The on-chain mempool accepts only the next 8 nonces per address, and prunes transactions older than one day.

## How do HyperCore and HyperEVM talk to each other?

Two mechanisms connect the layers, both exposed to Solidity as built-in calls.

**Read precompiles** live at addresses starting from `0x0000000000000000000000000000000000000800`. They return HyperCore data such as perp positions, spot balances, vault equity, staking delegations, oracle prices, and the L1 block number. The values are guaranteed to match the latest HyperCore state at the time the EVM block is constructed. Each call costs `2000 + 65 * (input_len + output_len)` gas.

**CoreWriter** is a system contract at `0x3333333333333333333333333333333333333333`. A contract calls it to emit a log that HyperCore processes as an action, such as placing an order or moving funds. A basic call uses about 47,000 gas. Order actions and vault transfers sent through CoreWriter are delayed on-chain by a few seconds so that HyperEVM cannot be used to bypass the L1 mempool.

Native transfers between the layers use system addresses. Sending HYPE to `0x2222222222222222222222222222222222222222` on HyperCore credits the same address on HyperEVM. Error code 10055 marks failures at the HyperCore and HyperEVM boundary, such as nonce errors or insufficient funds.

## What are API servers?

API servers are the public face of Hyperliquid. An API server listens to a node, keeps a local copy of chain state, and serves that state over REST and WebSocket. It does not validate.

![Hyperliquid order path from client to committed block](https://www.dwellir.com/img/hyperliquid/hyperliquid_order_path.webp)

Five steps: the client signs the action and sends it over REST or WebSocket; the non-validating API server keeps a local state copy and forwards to its node; the node gossips the transaction to validators on ports 4001 and 4002; HyperBFT orders and executes it in a committed block, final at once; the API server returns the L1 execution result, not an acknowledgement. The whole round trip is 0.2 s median and 0.9 s at the 99th percentile for a co-located client.

When you submit an action, the path is:

1. Your client sends the signed action to an API server.
2. The API server forwards it to its connected node.
3. The node gossips the transaction into HyperBFT consensus.
4. The transaction is included in a committed block.
5. The API server responds with the execution result from that block.

The response you receive is the L1 execution outcome, not an acknowledgement that the request was queued. That is why the 0.2 second median figure above covers the full round trip. API servers may disconnect WebSocket clients periodically without announcement. Automated clients should reconnect and use the snapshot sent on reconnect to fill any gap.

## What does a Hyperliquid node do?

Validators run HyperBFT and execute blocks. Anyone can run a non-validating node, which streams committed blocks from peers and executes them locally. The node binary is distributed through `hl-visor`, and started with `hl-visor run-non-validator`.

| Requirement     | Non-validating node                                |
| --------------- | -------------------------------------------------- |
| Hardware        | 16 vCPUs, 128 GB RAM, 500 GB SSD                   |
| Network         | Ports 4001 and 4002 open to the public for gossip  |
| Location        | Tokyo for the lowest latency to validators         |
| Disk write rate | About 100 GB of logs per day with default settings |

The Hyper Foundation runs a best-efforts non-validating node in AWS `apne1-az1` that qualified traders and infrastructure providers can peer with. Dwellir is one of the listed peering providers. If you run your own node, [Hyperliquid Peering](https://www.dwellir.com/docs/hyperliquid/peering) reserves a slot on Dwellir's peers so your node has a stable upstream.

### What a node writes to disk

A non-validating node is the only way to get some data. It writes protocol records under `~/hl/data`:

| Path                                        | Content                                                       | Flag                     |
| ------------------------------------------- | ------------------------------------------------------------- | ------------------------ |
| `replica_cmds/{start_time}/{date}/{height}` | Blocks with signed actions, responses, and consensus metadata | Default                  |
| `periodic_abci_states/{date}/{height}.rmp`  | Full state snapshot every 10,000 blocks                       | Default                  |
| `node_fills/hourly/{date}/{hour}`           | Fills in API format                                           | `--write-fills`          |
| `node_twap_statuses/{date}/{hour}`          | TWAP lifecycle statuses                                       | `--write-fills`          |
| `node_order_statuses/hourly/{date}/{hour}`  | Every order status change                                     | `--write-order-statuses` |
| `node_raw_book_diffs/hourly/{date}/{hour}`  | Every order-level book change                                 | `--write-raw-book-diffs` |
| `misc_events/hourly/{date}/{hour}`          | Staking, validator rewards, ledger updates                    | `--write-misc-events`    |

With `--batch-by-block`, each line is one block in the envelope `{local_time, block_time, block_number, events}`. The `block_number` in those envelopes is a sequential height. It is not the same value as the `abci_block.round` inside `replica_cmds`, because consensus rounds can skip.

Two flags turn a node into a local API: `--serve-eth-rpc` serves HyperEVM JSON-RPC on `localhost:3001/evm`, and `--serve-info` serves Info endpoint requests on `localhost:3001/info`. Neither replicates the historical time-series queries of the public API. The [data catalog](https://www.dwellir.com/docs/hyperliquid/data-catalog) documents each feed's schema and how Dwellir exposes it live and historically.

## What are the public rate limits?

The official API servers and RPC enforce per-IP limits. These are the numbers that decide when a project outgrows public infrastructure.

![Hyperliquid public rate limits by surface](https://www.dwellir.com/img/hyperliquid/hyperliquid_public_limits.webp)

REST info and exchange: 1,200 weight per minute per IP, with weight 2 for l2Book and clearinghouseState, 20 for most info calls, and 60 for userRole. WebSocket: 10 connections per IP, 1,000 subscriptions, 2,000 messages per minute, 10 unique users on user streams. EVM JSON-RPC at rpc.hyperliquid.xyz: 100 requests per minute, HTTP only. Your own node or a managed provider: no per-IP API limits, 16 vCPUs, 128 GB RAM, 500 GB SSD, about 100 GB of node output per day.

| Surface                                   | Limit                                                                                                                                                 |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| REST, info and exchange combined          | 1,200 weight per minute per IP                                                                                                                        |
| Info request weight                       | 2 for `l2Book`, `allMids`, `clearinghouseState`, `orderStatus`, `spotClearinghouseState`, `exchangeStatus`. 60 for `userRole`. 20 for everything else |
| Exchange request weight                   | `1 + floor(batch_length / 40)`                                                                                                                        |
| WebSocket connections                     | 10 per IP, 30 new connections per minute                                                                                                              |
| WebSocket subscriptions                   | 1,000 per IP, 10 unique users across user-specific subscriptions                                                                                      |
| WebSocket messages                        | 2,000 sent per minute, 100 in-flight post messages                                                                                                    |
| EVM JSON-RPC at `rpc.hyperliquid.xyz/evm` | 100 requests per minute                                                                                                                               |

Paginated info requests such as `userFills` add extra weight per 20 items returned, and `candleSnapshot` adds extra weight per 60 items. Hyperliquid's own guidance for large historical pulls is to use the S3 bucket rather than the API.

## When does public infrastructure stop being enough?

The public endpoints are designed for interactive use and light automation. You have outgrown them when any of these are true:

- **You poll faster than 1,200 weight per minute.** A bot that reads `clearinghouseState` and `l2Book` for a handful of markets every second uses the whole budget on its own.
- **You need more than 10 WebSocket connections or 1,000 subscriptions per IP.** Subscribing to trades and L2 books across every perp market already exceeds the ceiling. See [WebSocket subscription limits](https://www.dwellir.com/blog/hyperliquid-websocket-subscription-limits).
- **You index HyperEVM.** An indexer or backfill at 100 requests per minute takes days for work that should take minutes, and the official RPC has no WebSocket for new heads.
- **You need L4 order-level data or raw book diffs.** These are only written by a node. They are not on the public API.
- **You need history.** The API returns at most 500 items per time-range query and keeps limited depth. Backtests and research need the archive.

At that point there are two paths. Run your own non-validating node, with [peering](https://www.dwellir.com/docs/hyperliquid/peering) for a reliable upstream, or use a provider that runs nodes for you.

Dwellir runs Hyperliquid nodes and exposes every layer described above through one platform: [gRPC streams](https://www.dwellir.com/docs/hyperliquid/grpc) of the node-written feeds, a purpose-built [Order Book WebSocket](https://www.dwellir.com/docs/hyperliquid/order-book-server) for L2, L4, and trades, [HyperEVM JSON-RPC](https://www.dwellir.com/docs/hyperliquid/eth_call), the [Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint) with limits that scale by plan, and an [archive](https://www.dwellir.com/docs/hyperliquid/historical-data) of the raw node files back to January 2025. In Dwellir's published benchmark from Tokyo, the Order Book WebSocket delivered a 212 ms median update latency against 263 ms on the public API. See [pricing](https://www.dwellir.com/docs/hyperliquid/pricing) for plan limits and the Dedicated Node Cluster option.

## Related

- [Hyperliquid data catalog](https://www.dwellir.com/docs/hyperliquid/data-catalog): what the node writes and how each feed is exposed
- [Hyperliquid Peering](https://www.dwellir.com/docs/hyperliquid/peering): reserved gossip peers for your own node
- [Hyperliquid latency explained](https://www.dwellir.com/blog/hyperliquid-latency-explained): where the milliseconds go between node, API, and client
- [Hyperliquid docs: HyperCore overview](https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/overview)
- [Hyperliquid docs: HyperEVM](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm)
- [Hyperliquid docs: rate limits](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/rate-limits-and-user-limits)
- [Hyperliquid node repository](https://github.com/hyperliquid-dex/node)

---

## batchClearinghouseStates - HyperCore Info Endpoint

# batchClearinghouseStates - HyperCore Info Endpoint

Batch query perpetual account states for multiple users in a single request. This is a custom endpoint exclusive to Dwellir's HyperCore REST API — it is not available on standard Hyperliquid nodes.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `batchClearinghouseStates` endpoint is designed for applications that need account state for many users at once. It fans out individual `clearinghouseState` calls concurrently and aggregates the results, so you don't need to manage your own fan-out and error handling.

- **Portfolio Dashboards** — Fetch account states for all tracked wallets in one call
- **Risk Monitoring** — Monitor margin health across a fleet of trading accounts
- **Fund Management** — Aggregate position data across multiple sub-accounts or strategies
- **Multi-DEX Analytics** — Query all DEXes for each user with a single `ALL_DEXES` request

## Billing

`batchClearinghouseStates` is billed by the number of distinct valid wallets in the batch, not as one response per HTTP request.
A request with `1,000` distinct valid wallets counts as `1,000` responses/API credits.

Wallets listed in `failed_wallets` still count because an upstream lookup was performed for them. Duplicate and malformed wallet entries are removed before the batch runs and do not count. Non-success HTTP responses are not charged.

## Request Parameters

- `type` (`string, required`): parameter: Must be `"batchClearinghouseStates"`
- `users` (`string[], required`): parameter: Non-empty list of wallet addresses
- `dex` (`string, optional`): parameter: DEX name. Omit for native DEX. Set to `"ALL_DEXES"` to query all DEXes.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "batchClearinghouseStates",
  "users": [
    "0x00f2548cf639e54420e501a35346e8458989e6bd",
    "0x010461c14e146ac35fe42271bdc1134ee31c703a",
    "0x02159593e155250288a7a1dd5257fc217601ceee"
  ]
}'
```

## Response Fields

- `successful_states` (`[address, state][], required`): Array of two-element tuples. `address` is the wallet address; `state` is the raw upstream `clearinghouseState` object.
- `failed_wallets` (`string[], required`): Addresses whose upstream call failed (timeout, non-200, etc.).

## Successful Response

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "marginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMarginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMaintenanceMarginUsed": "0.0",
        "withdrawable": "0.0",
        "assetPositions": [],
        "time": 1771587392044
      }
    ],
    [
      "0x010461c14e146ac35fe42271bdc1134ee31c703a",
      {
        "marginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMarginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMaintenanceMarginUsed": "0.0",
        "withdrawable": "0.0",
        "assetPositions": [],
        "time": 1771587392044
      }
    ]
  ],
  "failed_wallets": []
}
```

## Response — Single DEX

Both fields are always present. Order matches input order.

| Field               | Type                 | Description                                                                                                            |
| ------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `successful_states` | `[address, state][]` | Array of two-element tuples. `address` is the wallet address; `state` is the raw upstream `clearinghouseState` object. |
| `failed_wallets`    | `string[]`           | Addresses whose upstream call failed (timeout, non-200, etc.).                                                         |

### Success Response

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "marginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMarginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMaintenanceMarginUsed": "0.0",
        "withdrawable": "0.0",
        "assetPositions": [],
        "time": 1771587392044
      }
    ],
    [
      "0x010461c14e146ac35fe42271bdc1134ee31c703a",
      {
        "marginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMarginSummary": {
          "accountValue": "0.0",
          "totalNtlPos": "0.0",
          "totalRawUsd": "0.0",
          "totalMarginUsed": "0.0"
        },
        "crossMaintenanceMarginUsed": "0.0",
        "withdrawable": "0.0",
        "assetPositions": [],
        "time": 1771587392044
      }
    ]
  ],
  "failed_wallets": []
}
```

### Partial Failure Response

If some calls fail, those addresses appear in `failed_wallets`:

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "marginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
        "crossMarginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
        "crossMaintenanceMarginUsed": "0.0",
        "withdrawable": "0.0",
        "assetPositions": [],
        "time": 1771587392044
      }
    ]
  ],
  "failed_wallets": ["0x010461c14e146ac35fe42271bdc1134ee31c703a"]
}
```

## Response — ALL\_DEXES

When `dex` is set to `"ALL_DEXES"`, the response shape changes. Each user's state is an object keyed by DEX name.

| Field               | Type                   | Description                                                                                                                    |
| ------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `successful_states` | `[address, dex_map][]` | Array of two-element tuples. `dex_map` is an object keyed by DEX name, each value being the `clearinghouseState` for that DEX. |
| `failed_wallets`    | `string[]`             | Addresses where **all** DEX calls failed.                                                                                      |

Key semantics:

- The native DEX appears under the key `"native"`.
- **Partial success**: if some DEX calls succeed and others fail for a user, the user is included in `successful_states` with only the DEXes that responded. They do **not** appear in `failed_wallets`.
- **DEX truncation**: if the chain reports more DEXes than `max_dexes`, the list is silently truncated. The response may not cover every DEX on the chain.

### ALL\_DEXES Response Example

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "native": {
          "marginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
          "crossMarginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
          "crossMaintenanceMarginUsed": "0.0",
          "withdrawable": "0.0",
          "assetPositions": [],
          "time": 1771587392044
        },
        "xyz": {
          "marginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
          "crossMarginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
          "crossMaintenanceMarginUsed": "0.0",
          "withdrawable": "0.0",
          "assetPositions": [],
          "time": 1771587392044
        }
      }
    ]
  ],
  "failed_wallets": ["0x010461c14e146ac35fe42271bdc1134ee31c703a"]
}
```

## Common Use Cases

### 1. Multi-Account Dashboard

Fetch and display account states for a set of tracked wallets:

```javascript
async function getMultiAccountDashboard(wallets) {
  const result = await getBatchClearinghouseStates(wallets);

  const dashboard = result.successful_states.map(([address, state]) => ({
    address,
    accountValue: parseFloat(state.marginSummary.accountValue),
    marginUsed: parseFloat(state.marginSummary.totalMarginUsed),
    withdrawable: parseFloat(state.marginSummary.withdrawable),
    positions: state.assetPositions.length
  }));

  const totalValue = dashboard.reduce((sum, a) => sum + a.accountValue, 0);
  console.log(`Total across ${dashboard.length} accounts: $${totalValue.toFixed(2)}`);

  if (result.failed_wallets.length > 0) {
    console.warn(`Failed to fetch: ${result.failed_wallets.join(', ')}`);
  }

  return dashboard;
}
```

### 2. Cross-DEX Position Aggregation

Query all DEXes for a set of users and aggregate positions:

```javascript
async function getCrossDexPositions(wallets) {
  const result = await getBatchClearinghouseStates(wallets, 'ALL_DEXES');

  for (const [address, dexMap] of result.successful_states) {
    console.log(`\n=== ${address} ===`);
    for (const [dexName, state] of Object.entries(dexMap)) {
      const value = parseFloat(state.marginSummary.accountValue);
      const positions = state.assetPositions.length;
      console.log(`  ${dexName}: $${value.toFixed(2)} (${positions} positions)`);
    }
  }
}
```

### 3. Batch Risk Monitoring

Monitor margin utilization across many accounts and flag those at risk:

```javascript
async function batchRiskCheck(wallets) {
  const result = await getBatchClearinghouseStates(wallets);
  const alerts = [];

  for (const [address, state] of result.successful_states) {
    const margin = state.marginSummary;
    const accountValue = parseFloat(margin.accountValue);
    const marginUsed = parseFloat(margin.totalMarginUsed);
    const utilization = accountValue > 0 ? (marginUsed / accountValue) * 100 : 0;

    if (utilization > 80) {
      alerts.push({ address, utilization: utilization.toFixed(2), accountValue });
    }
  }

  // Also flag wallets that failed to respond
  for (const address of result.failed_wallets) {
    alerts.push({ address, error: 'Failed to fetch state' });
  }

  return alerts;
}
```

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state for a single user
- [**batchSpotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/batch-spot-clearinghouse-state): Batch query spot balances for multiple users
- [**batchPortfolioState**](https://www.dwellir.com/docs/hyperliquid/batch-portfolio-state): Batch query perp state, spot balances, and account mode
- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state) — Get single-user perp state, spot balances, and account mode in one request
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot trading account state
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get user's open orders
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata

***

*Batch query Hyperliquid account states with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## batchPortfolioState - HyperCore Info Endpoint

# batchPortfolioState - HyperCore Info Endpoint

Batch query perpetual state, spot balances, and account abstraction mode for multiple users in a single request. This is a Dwellir custom endpoint. Standard Hyperliquid nodes do not serve it.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `batchPortfolioState` endpoint serves applications that need a full portfolio view for many users at once. It fans out `portfolioState` composition per user and aggregates the results. You do not coordinate clearinghouse, spot, and abstraction calls yourself.

Unified and portfolio-margin accounts return abstraction mode and spot state next to perp state.

- **Portfolio Dashboards**: Load perp state, spot balances, and account mode for every tracked wallet in one call
- **Risk Systems**: Combine derivative exposure with spot collateral and account abstraction mode across a fleet
- **Fund Management**: Aggregate sub-accounts without stitching three responses per wallet
- **Multi-DEX Views**: Use `dex: "ALL_DEXES"` to inspect the native DEX and all operational HIP-3 DEXs together

## Billing

`batchPortfolioState` is billed by the number of upstream responses it aggregates, not as one response per HTTP request.

- `{"type":"batchPortfolioState","users":["0x00f2548cf639e54420e501a35346e8458989e6bd"]}` counts as `3` responses/API credits.
- `{"type":"batchPortfolioState","users":["0x00f2548cf639e54420e501a35346e8458989e6bd","0x010461c14e146ac35fe42271bdc1134ee31c703a"]}` counts as `6` responses/API credits.
- `{"type":"batchPortfolioState","users":["0x00f2548cf639e54420e501a35346e8458989e6bd"],"dex":"ALL_DEXES"}` counts as `1 + users * (N + 2)` responses/API credits, where `N` is the number of keys in each returned `clearinghouseState` map, including `"native"`. For example, one user with `10` returned DEX keys counts as `13` responses/API credits.

Wallets listed in `failed_wallets` still count because an upstream lookup was performed for them. Duplicate and malformed wallet entries are removed before the batch runs and do not count. DEX discovery counts even when served from the gateway cache. Non-success HTTP responses are not charged.

## Request Parameters

- `type` (`string, required`): parameter: Must be `"batchPortfolioState"`
- `users` (`string[], required`): parameter: Non-empty list of wallet addresses
- `dex` (`string, optional`): parameter: HIP-3 market identifier. Query "`perpDexs`" first to discover supported DEX names. Omit to query the main Hyperliquid DEX, or use "`ALL_DEXES`" to aggregate the main DEX plus all operational HIP-3 DEXs.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "batchPortfolioState",
  "users": [
    "0x00f2548cf639e54420e501a35346e8458989e6bd",
    "0x010461c14e146ac35fe42271bdc1134ee31c703a"
  ]
}'
```

## Response Fields

- `successful_states` (`[address, payload][], required`): Array of two-element tuples. `payload` is the `portfolioState` object for that user (`clearinghouseState`, `spotClearinghouseState`, `userAbstraction`).
- `failed_wallets` (`string[], required`): Addresses where any composed branch failed.

## Successful Response

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "clearinghouseState": {
          "marginSummary": {
            "accountValue": "555.13644",
            "totalMarginUsed": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "555.13644"
          },
          "crossMarginSummary": {
            "accountValue": "555.13644",
            "totalMarginUsed": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "555.13644"
          },
          "crossMaintenanceMarginUsed": "0.0",
          "withdrawable": "555.13644",
          "assetPositions": [],
          "time": 1776448114752
        },
        "spotClearinghouseState": {
          "balances": [
            {
              "coin": "USDC",
              "token": 0,
              "total": "12.27568764",
              "hold": "0.0",
              "entryNtl": "0.0"
            }
          ]
        },
        "userAbstraction": "default"
      }
    ]
  ],
  "failed_wallets": []
}
```

## Response: Single DEX

Both fields are always present. Order matches input order after malformed and duplicate addresses are dropped.

| Field               | Type                   | Description                                                                                                                                                 |
| ------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `successful_states` | `[address, payload][]` | Array of two-element tuples. `payload` is the `portfolioState` object for that user: `clearinghouseState`, `spotClearinghouseState`, and `userAbstraction`. |
| `failed_wallets`    | `string[]`             | Addresses where any composed branch failed. Other users in the same request can still succeed.                                                              |

### Success Response

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "clearinghouseState": {
          "marginSummary": {
            "accountValue": "555.13644",
            "totalMarginUsed": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "555.13644"
          },
          "crossMarginSummary": {
            "accountValue": "555.13644",
            "totalMarginUsed": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "555.13644"
          },
          "crossMaintenanceMarginUsed": "0.0",
          "withdrawable": "555.13644",
          "assetPositions": [],
          "time": 1776448114752
        },
        "spotClearinghouseState": {
          "balances": [
            {
              "coin": "USDC",
              "token": 0,
              "total": "12.27568764",
              "hold": "0.0",
              "entryNtl": "0.0"
            }
          ]
        },
        "userAbstraction": "default"
      }
    ]
  ],
  "failed_wallets": []
}
```

### Partial Failure Response

A user lands in `failed_wallets` when any composed branch fails:

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "clearinghouseState": {
          "marginSummary": {
            "accountValue": "555.13644",
            "totalMarginUsed": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "555.13644"
          },
          "crossMarginSummary": {
            "accountValue": "555.13644",
            "totalMarginUsed": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "555.13644"
          },
          "crossMaintenanceMarginUsed": "0.0",
          "withdrawable": "555.13644",
          "assetPositions": [],
          "time": 1776448114752
        },
        "spotClearinghouseState": {
          "balances": [
            {
              "coin": "USDC",
              "token": 0,
              "total": "12.27568764",
              "hold": "0.0",
              "entryNtl": "0.0"
            }
          ]
        },
        "userAbstraction": "unifiedAccount"
      }
    ]
  ],
  "failed_wallets": ["0x010461c14e146ac35fe42271bdc1134ee31c703a"]
}
```

## The `dex` Parameter

By default, each successful payload returns the main Hyperliquid perpetuals DEX state, spot balances, and account abstraction mode. To target a specific HIP-3 market, pass a DEX name returned by [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs). To aggregate across the native DEX and all operational HIP-3 markets, use `dex: "ALL_DEXES"`.

| `dex` value                                                                      | Returns                                                                                                                                          |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| *(omitted)*                                                                      | Native Hyperliquid perp state plus spot balances and account mode for each user                                                                  |
| Any DEX name returned by [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs) | The named HIP-3 DEX state plus spot balances and account mode for each user                                                                      |
| `"ALL_DEXES"`                                                                    | A DEX map of perp state for the native DEX plus every operational HIP-3 market, alongside top-level spot balances and account mode for each user |

### `ALL_DEXES` Request

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "batchPortfolioState",
  "users": [
    "0x00f2548cf639e54420e501a35346e8458989e6bd"
  ],
  "dex": "ALL_DEXES"
}'
```

### `ALL_DEXES` Response Shape

When `dex` is `"ALL_DEXES"`, each payload's `clearinghouseState` becomes an object keyed by DEX name. `spotClearinghouseState` and `userAbstraction` remain at the top level of that payload. The native DEX always appears under the `"native"` key. Additional keys are dynamic and correspond to operational HIP-3 DEX names returned by [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs), so discover them instead of hardcoding a single example value.

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "clearinghouseState": {
          "native": {
            "marginSummary": {
              "accountValue": "555.13644",
              "totalMarginUsed": "0.0",
              "totalNtlPos": "0.0",
              "totalRawUsd": "555.13644"
            },
            "crossMarginSummary": {
              "accountValue": "555.13644",
              "totalMarginUsed": "0.0",
              "totalNtlPos": "0.0",
              "totalRawUsd": "555.13644"
            },
            "crossMaintenanceMarginUsed": "0.0",
            "withdrawable": "555.13644",
            "assetPositions": [],
            "time": 1776448114752
          },
          "<dex_name>": {
            "marginSummary": {
              "accountValue": "0.0",
              "totalMarginUsed": "0.0",
              "totalNtlPos": "0.0",
              "totalRawUsd": "0.0"
            },
            "crossMarginSummary": {
              "accountValue": "0.0",
              "totalMarginUsed": "0.0",
              "totalNtlPos": "0.0",
              "totalRawUsd": "0.0"
            },
            "crossMaintenanceMarginUsed": "0.0",
            "withdrawable": "0.0",
            "assetPositions": [],
            "time": 1776448114649
          }
        },
        "spotClearinghouseState": {
          "balances": [
            {
              "coin": "USDC",
              "token": 0,
              "total": "12.27568764",
              "hold": "0.0",
              "entryNtl": "0.0"
            }
          ]
        },
        "userAbstraction": "default"
      }
    ]
  ],
  "failed_wallets": []
}
```

## What `batchPortfolioState` Composes

Each successful payload is equivalent to one [`portfolioState`](https://www.dwellir.com/docs/hyperliquid/portfolio-state) response:

- [`clearinghouseState`](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state): perp positions and margin data
- [`spotClearinghouseState`](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state): spot balances
- [`userAbstraction`](https://www.dwellir.com/docs/hyperliquid/user-abstraction): account abstraction mode

When `dex` is `"ALL_DEXES"`, the clearinghouse branch reuses the `ALL_DEXES` aggregation and keeps the spot and abstraction data at the top level of each payload.

## Common Use Cases

### 1. Multi-Account Portfolio Overview

```javascript
async function getBatchPortfolioOverview(wallets) {
  const result = await getBatchPortfolioState(wallets, 'ALL_DEXES');

  return result.successful_states.map(([address, portfolio]) => ({
    address,
    abstraction: portfolio.userAbstraction,
    perpDexes: Object.keys(portfolio.clearinghouseState),
    spotBalances: portfolio.spotClearinghouseState.balances.length
  }));
}
```

### 2. Merge Spot and Perp State for Many Wallets

```javascript
async function getDashboardStates(wallets) {
  const result = await getBatchPortfolioState(wallets);

  return result.successful_states.map(([address, portfolio]) => ({
    address,
    accountValue: parseFloat(portfolio.clearinghouseState.marginSummary.accountValue),
    withdrawable: parseFloat(portfolio.clearinghouseState.withdrawable),
    balances: portfolio.spotClearinghouseState.balances,
    accountMode: portfolio.userAbstraction
  }));
}
```

## Related Endpoints

- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state): Get perp state, spot balances, and account mode for a single user
- [**batchClearinghouseStates**](https://www.dwellir.com/docs/hyperliquid/batch-clearinghouse-states): Batch query perpetual account states
- [**batchSpotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/batch-spot-clearinghouse-state): Batch query spot balances
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state): Get perpetual account state, including `ALL_DEXES` support
- [**userAbstraction**](https://www.dwellir.com/docs/hyperliquid/user-abstraction): Get account abstraction mode only

***

*Batch query full Hyperliquid portfolio state with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## batchSpotClearinghouseState - HyperCore Info Endpoint

# batchSpotClearinghouseState - HyperCore Info Endpoint

Batch query spot account balances for multiple users in a single request. This is a Dwellir custom endpoint. Standard Hyperliquid nodes do not serve it.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `batchSpotClearinghouseState` endpoint serves applications that need spot balances for many users at once. It fans out individual `spotClearinghouseState` calls concurrently and aggregates the results. You do not manage fan-out or per-wallet error handling yourself.

Spot state is not DEX-scoped. There is no `dex` field.

- **Portfolio Dashboards**: Fetch spot balances for all tracked wallets in one call
- **Treasury Monitoring**: Track available and held balances across a fleet of accounts
- **Trade Validation**: Check whether many wallets have enough free balance before placing orders
- **Fund Management**: Aggregate token holdings across sub-accounts or strategies

## Billing

`batchSpotClearinghouseState` is billed by the number of distinct valid wallets in the batch, not as one response per HTTP request.
A request with `1,000` distinct valid wallets counts as `1,000` responses/API credits.

Wallets listed in `failed_wallets` still count because an upstream lookup was performed for them. Duplicate and malformed wallet entries are removed before the batch runs and do not count. Non-success HTTP responses are not charged.

## Request Parameters

- `type` (`string, required`): parameter: Must be `"batchSpotClearinghouseState"`
- `users` (`string[], required`): parameter: Non-empty list of wallet addresses

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "batchSpotClearinghouseState",
  "users": [
    "0x00f2548cf639e54420e501a35346e8458989e6bd",
    "0x010461c14e146ac35fe42271bdc1134ee31c703a"
  ]
}'
```

## Response Fields

- `successful_states` (`[address, state][], required`): Array of two-element tuples. `address` is the wallet address; `state` is the raw upstream `spotClearinghouseState` object.
- `failed_wallets` (`string[], required`): Addresses whose upstream call failed (timeout, non-200, etc.).

## Successful Response

```json
{
  "successful_states": [
    [
      "0x00f2548cf639e54420e501a35346e8458989e6bd",
      {
        "balances": [
          {
            "coin": "USDC",
            "token": 0,
            "total": "0.01261784",
            "hold": "0.0",
            "entryNtl": "0.0"
          }
        ]
      }
    ],
    [
      "0x010461c14e146ac35fe42271bdc1134ee31c703a",
      {
        "balances": [
          {
            "coin": "USDC",
            "token": 0,
            "total": "12.27568764",
            "hold": "0.0",
            "entryNtl": "0.0"
          }
        ]
      }
    ]
  ],
  "failed_wallets": []
}
```

## Common Use Cases

### 1. Multi-Account Spot Dashboard

Fetch and display spot balances for a set of tracked wallets:

```javascript
async function getMultiAccountSpotBalances(wallets) {
  const result = await getBatchSpotClearinghouseState(wallets);

  const dashboard = result.successful_states.map(([address, state]) => {
    const holdings = state.balances
      .filter((balance) => parseFloat(balance.total) > 0)
      .map((balance) => ({
        token: balance.coin,
        total: parseFloat(balance.total),
        available: parseFloat(balance.total) - parseFloat(balance.hold)
      }));

    return { address, holdings };
  });

  if (result.failed_wallets.length > 0) {
    console.warn(`Failed to fetch: ${result.failed_wallets.join(', ')}`);
  }

  return dashboard;
}
```

### 2. Available Balance Check Across Wallets

Calculate free USDC for every wallet in the batch:

```javascript
async function getAvailableUsdc(wallets) {
  const result = await getBatchSpotClearinghouseState(wallets);

  return result.successful_states.map(([address, state]) => {
    const usdc = state.balances.find((balance) => balance.coin === 'USDC');
    const total = usdc ? parseFloat(usdc.total) : 0;
    const hold = usdc ? parseFloat(usdc.hold) : 0;

    return {
      address,
      available: total - hold,
      hold
    };
  });
}
```

## Related Endpoints

- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state): Get spot balances for a single user
- [**batchClearinghouseStates**](https://www.dwellir.com/docs/hyperliquid/batch-clearinghouse-states): Batch query perpetual account states
- [**batchPortfolioState**](https://www.dwellir.com/docs/hyperliquid/batch-portfolio-state): Batch query perp state, spot balances, and account mode
- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state): Get single-user perp state, spot balances, and account mode
- [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta): Get spot trading asset metadata

***

*Batch query Hyperliquid spot balances with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## batchModify payload - Batch Order Modifications

# batchModify payload - Batch Order Modifications

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `batchModify` payload records multiple order modification requests grouped in one native Hyperliquid action.

## Sample Data

```json
{
  "signature": {
    "r": "0x34b4fe28e091111949d4925ae53c10c552e859523debcafa41048767ca88bace",
    "s": "0x48ecd1cd140ecb3d91bfac13410794e5cdbf3221fcf4371a293a737ffab4b3d0",
    "v": 28
  },
  "action": {
    "type": "batchModify",
    "modifies": [
      {
        "oid": 291708433915,
        "order": {
          "a": 168,
          "b": false,
          "p": "0.03302",
          "s": "8000",
          "r": false,
          "t": {
            "limit": {
              "tif": "Alo"
            }
          }
        }
      }
    ]
  },
  "nonce": 1768146913007
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x0fd9bc835e9ad5bc115304332644bd013800d468f99df48eb3a267d61d9eafa6)

## Field Reference

### Action Fields

| Field      | Type   | Description                   |
| ---------- | ------ | ----------------------------- |
| `type`     | string | Always `"batchModify"`        |
| `modifies` | array  | Array of modification objects |

### Modify Object Fields

| Field   | Type   | Description                                                                                        |
| ------- | ------ | -------------------------------------------------------------------------------------------------- |
| `oid`   | number | Order ID of the order to modify                                                                    |
| `order` | object | New order parameters (same structure as [order](https://www.dwellir.com/docs/hyperliquid/order) action) |

### Order Fields

| Field | Type    | Description                            |
| ----- | ------- | -------------------------------------- |
| `a`   | number  | Asset index                            |
| `b`   | boolean | Side: `true` for buy, `false` for sell |
| `p`   | string  | New limit price                        |
| `s`   | string  | New size                               |
| `r`   | boolean | Reduce-only flag                       |
| `t`   | object  | Order type configuration               |

## Response Handling

Do not infer an all-or-nothing result from the action payload. Pair the batch with its response and inspect each returned status before deciding which modifications succeeded or failed.

## Use Cases

### Market Making Quote Updates

Observe bid and ask quote updates submitted together to maintain a spread:

```python
def process_batchModify_action(action):
    modifies = action.get('modifies', [])

    for mod in modifies:
        oid = mod['oid']
        new_price = mod['order']['p']
        new_size = mod['order']['s']
        side = 'BUY' if mod['order']['b'] else 'SELL'

        print(f"Modified {oid}: {side} {new_size} @ {new_price}")
```

### Spread Analysis

Track how market makers adjust their quotes in response to price movements.

### Quote Refresh Rate Monitoring

Measure how frequently market makers update their orders.

## Related Action Payloads

- [order](https://www.dwellir.com/docs/hyperliquid/order) - New order payloads
- [modify](https://www.dwellir.com/docs/hyperliquid/modify) - Single-order modifications
- [cancel](https://www.dwellir.com/docs/hyperliquid/cancel) - Order cancellations

---

## BBO (Best Bid/Offer) - Top of Book

# BBO (Best Bid/Offer) - Top of Book

Hyperliquid's public API has a dedicated `bbo` WebSocket channel, and Dwellir mirrors it natively. Subscribe with `{"type": "bbo", "coin": "BTC"}` (coin only, no params) and receive the same `{"channel": "bbo", ...}` payload shape as the public feed. It's a drop-in target for clients written against the public API.

Under the hood `bbo` is `l2Book` top-of-book (`nLevels=1`) with always-on dedup: a message is emitted only when the top bid or ask actually changes, at most once per block. It is functionally equivalent to `{"type": "l2Book", "nLevels": 1, "strict": true}`, just in the public payload shape.

Stream the best bid and best ask for any trading pair with minimal bandwidth, ideal for price tracking, execution triggers, and spread monitoring.

Clone our complete examples: [github.com/dwellir-public/hyperliquid-orderbook-server-code-examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)

## How to Subscribe

Send a subscription message to the WebSocket endpoint:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "bbo",
    "coin": "BTC"
  }
}
```

### Subscription Parameters

| Parameter | Type   | Required | Default | Description                                                                   |
| --------- | ------ | -------- | ------- | ----------------------------------------------------------------------------- |
| `type`    | string | Yes      | -       | Must be `"bbo"`                                                               |
| `coin`    | string | Yes      | -       | Trading pair symbol (e.g., `"BTC"`, `"ETH"`, `"xyz:MSTR"`, `"@150"`, `"#10"`) |

Unlike `l2Book`, the `bbo` subscription takes **only** `coin`. It always serves raw top-of-book. `nSigFigs`, `mantissa`, and `nLevels` are ignored (not rejected), matching the public feed. If you need rounded or aggregated top-of-book, use the [`l2Book` with `nLevels=1`](#aggregated-alternative-l2book-with-nlevels1) approach below instead.

### Coin Format by Market Type

The `coin` field accepts different formats depending on the market:

| Market                           | Format         | Example                   | Notes                             |
| -------------------------------- | -------------- | ------------------------- | --------------------------------- |
| Standard perpetual               | Symbol         | `"BTC"`, `"ETH"`, `"SOL"` | No prefix needed                  |
| HIP-3 perpetual (permissionless) | `xyz:<symbol>` | `"xyz:MSTR"`              | Use full label with `xyz:` prefix |
| Spot                             | `@<index>`     | `"@150"`                  | Spot asset index                  |
| HIP-4 outcome                    | `#<encoding>`  | `"#10"`, `"#31"`          | Encoded outcome + side            |

#### Subscription Examples

Standard perpetual
HIP-3 perpetual
Spot
HIP-4 outcome

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "bbo",
    "coin": "BTC"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "bbo",
    "coin": "xyz:MSTR"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "bbo",
    "coin": "@150"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "bbo",
    "coin": "#31"
  }
}
```

For HIP-3 (permissionless perpetuals) markets, use the full coin label format with the `xyz:` prefix. For example, use `"xyz:MSTR"` for the MicroStrategy perpetual, not just `"MSTR"`. Standard perpetuals like BTC and ETH do not require a prefix.

For spot markets, use the `@{index}` format where the index is the spot asset index. For example, use `"@150"` for a specific spot market. If an available market is not accepted, contact support to confirm that it is enabled on your endpoint.

[HIP-4 outcome markets](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta) use the `#<encoding>` format. The encoding is derived from the outcome ID and binary side:

```
encoding = 10 * outcome + side
```

Only `side` `0` and `side` `1` are valid. For example, `"#10"` is outcome `1`, side `0`; `"#31"` is outcome `3`, side `1`. The same encoding maps to three representations:

- Outcome spot coin: `#<encoding>` (used here)
- Outcome token name: `+<encoding>`
- Outcome asset ID: `100_000_000 + encoding`

Live outcome IDs are returned by the [`outcomeMeta`](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta) info response. If an available outcome coin is not accepted, contact support to confirm that it is enabled on your endpoint.

The first websocket message after subscribing is a `subscriptionResponse`; subsequent messages carry the `bbo` payloads.

## Request Parameters

- `type` (`string, required`): Subscription parameter: Must be `"bbo"`
- `coin` (`string, required`): Subscription parameter: Trading pair symbol. Standard perpetual: `"BTC"`. HIP-3 perpetual: `"xyz:MSTR"`. Spot: `"@150"`. HIP-4 outcome: `"#10"` (encoding = `10 * outcome + side`). This is the only meaningful parameter; `nSigFigs`, `mantissa`, and `nLevels` are ignored.

## Request Example

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "bbo",
    "coin": "BTC"
  }
}
```

## Response Fields

- `channel` (`string, required`): Always `"bbo"` for this subscription type
- `data.coin` (`string, required`): Trading pair symbol
- `data.time` (`number, required`): Snapshot block time, Unix milliseconds
- `data.bbo` (`array, required`): Two-element array `[bid, ask]`, one level each, not the nested `levels: [[...], [...]]` of `l2Book`
- `bbo[0]` (`object | null, required`): Best bid (highest buy price), or `null` if no resting bids
- `bbo[1]` (`object | null, required`): Best ask (lowest sell price), or `null` if no resting asks

## Successful Response

```json
{
  "channel": "bbo",
  "data": {
    "coin": "BTC",
    "time": 1751427259657,
    "bbo": [
      {"px": "106217.0", "sz": "0.001", "n": 1},
      {"px": "106233.0", "sz": "0.26739", "n": 3}
    ]
  }
}
```

## Response Field Reference

```json
{
  "channel": "bbo",
  "data": {
    "coin": "BTC",
    "time": 1751427259657,
    "bbo": [
      {"px": "106217.0", "sz": "0.001", "n": 1},
      {"px": "106233.0", "sz": "0.26739", "n": 3}
    ]
  }
}
```

| Field       | Type           | Description                                                                                             |
| ----------- | -------------- | ------------------------------------------------------------------------------------------------------- |
| `channel`   | string         | Always `"bbo"` for this subscription type                                                               |
| `data.coin` | string         | Trading pair symbol                                                                                     |
| `data.time` | number         | Snapshot block time, Unix milliseconds                                                                  |
| `data.bbo`  | array          | Two-element array `[bid, ask]`, one level each, **not** the nested `levels: [[...], [...]]` of `l2Book` |
| `bbo[0]`    | object \| null | Best bid (highest buy price), or `null` if no resting bids                                              |
| `bbo[1]`    | object \| null | Best ask (lowest sell price), or `null` if no resting asks                                              |

### Level Object Fields

| Field | Type   | Description                               |
| ----- | ------ | ----------------------------------------- |
| `px`  | string | Price level                               |
| `sz`  | string | Total size at this price level            |
| `n`   | number | Number of orders aggregated at this level |

A side with no resting orders serializes as `null`, so always null-check before reading a level:

```json
{"channel": "bbo", "data": {"coin": "BTC", "time": 1751427259657, "bbo": [{"px": "106217.0", "sz": "0.001", "n": 1}, null]}}
```

## Semantics

- **On-change only:** a message is sent only when the top bid or ask changes (price, size, or order count). Identical top-of-book across blocks is suppressed.
- **Snapshot-based:** like `l2Book`, `bbo` is computed from the per-block snapshot, not an incremental stream. A dropped broadcast recovers on the next snapshot, so a lagging client is not torn down (unlike `trades`/`l4Book`).
- **Timestamp:** `time` is the snapshot's block time in milliseconds.
- **Outcome markets:** for HIP-4 outcome coins, the top-of-book reflects the merged two-sided book (the `1 - p` counterpart is folded in), consistent with `l2Book`.

## Dwellir BBO vs Public Hyperliquid BBO

Dwellir's `bbo` subscription mirrors the public Hyperliquid `bbo` WebSocket channel: the same subscribe message and the same `{"channel": "bbo", "data": {"coin", "time", "bbo": [bid, ask]}}` payload shape. Clients written against the public feed work unchanged.

The difference is delivery, not data: Dwellir's `bbo` is snapshot-based and deduped (emitted only when top-of-book changes, at most once per block), so a lagging client recovers on the next snapshot instead of being torn down.

## Aggregated Alternative: `l2Book` with `nLevels=1`

The native `bbo` subscription always serves raw top-of-book. When you instead want **rounded or aggregated** top-of-book (for example to reduce update frequency, or to keep a single unified `l2Book` payload shape across all depths), subscribe to `l2Book` with `nLevels=1` and the desired `nSigFigs`:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC",
    "nSigFigs": 5,
    "nLevels": 1
  }
}
```

This returns exactly one bid and one ask level in the standard `l2Book` `levels: [[bid], [ask]]` shape (see the [L2 Order Book](https://www.dwellir.com/docs/hyperliquid/l2-book) page). `nLevels` is a Dwellir-specific optimisation not available on the public Hyperliquid API.

### Understanding `nSigFigs`

`nSigFigs` controls price aggregation. Use `5` for full granularity (matching what the native `bbo` channel returns); lower values aggregate prices and may not reflect the true best level.

| nSigFigs | BTC Example | Effect                                  |
| -------- | ----------- | --------------------------------------- |
| 5        | $106,217    | Most granular - individual price points |
| 4        | $106,200    | Moderate aggregation                    |
| 3        | $106,000    | Coarse aggregation                      |
| 2        | $110,000    | Very coarse - major levels only         |

We tested `l2Book(nLevels=1, nSigFigs=5)` against the public `bbo` channel and confirmed **100% price match** across BTC, ETH, and SOL.

| Source                            | bid\_px    | ask\_px    | Format |
| --------------------------------- | ---------- | ---------- | ------ |
| Dwellir `l2Book(nLevels=1)`       | `"85.426"` | `"85.427"` | Same   |
| Public Hyperliquid `bbo`          | `"85.426"` | `"85.427"` | Same   |
| Public Hyperliquid `l2Book` (top) | `"85.426"` | `"85.427"` | Same   |

Sizes (`sz`) may differ slightly between any two connections due to update timing. This is expected and applies to any two independent WebSocket connections.

## Use Cases

### Price Feeds & Tickers

Display live mid-price or last price with minimal data overhead.

### Spread Monitoring

Track bid-ask spread in real-time for market quality assessment.

### Execution Triggers

Fire orders when the best bid or ask crosses a threshold.

### Multi-Coin Dashboards

Subscribe to BBO for many coins simultaneously with low bandwidth (1 level per coin vs 20).

### Latency-Sensitive Strategies

Smaller payloads = faster parsing. BBO messages are \~10x smaller than full 20-level book updates.

## Subscription Management

### Switching Between BBO and Full Depth

```python
# Subscribe to BBO
await websocket.send(json.dumps({
    "method": "subscribe",
    "subscription": {"type": "bbo", "coin": "BTC"}
}))

# Later, switch to full depth (20 levels)
await websocket.send(json.dumps({
    "method": "unsubscribe",
    "subscription": {"type": "bbo", "coin": "BTC"}
}))

await websocket.send(json.dumps({
    "method": "subscribe",
    "subscription": {"type": "l2Book", "coin": "BTC", "nSigFigs": 5, "nLevels": 20}
}))
```

## Get Access

Ready to integrate real-time Hyperliquid BBO data?

- **[Volume Calculator](https://www.dwellir.com/hyperliquid-orderbook#calculator)** - Estimate monthly message volume
- **[Contact Sales](mailto:support@dwellir.com)** - Get your WebSocket credentials
- **[Dashboard](https://dashboard.dwellir.com)** - Manage your subscription

***

*Stream institutional-grade Hyperliquid order book data with Dwellir's ultra-low latency infrastructure.*

---

## borrowLend payload - Borrow and Lend Operations

# borrowLend payload - Borrow and Lend Operations

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `borrowLend` payload records a borrow or lend operation in Hyperliquid's lending protocol.

## Sample Data

```json
{
  "signature": {
    "r": "0x73fe72e61a4a23d81cfaf36a5a313266a7f990fe5782bbd210b2d3ef1cd3d1c0",
    "s": "0x2971452d4fae3a4d9275abf2ff8f4347c79b414e4f267d4ed05c13c28c029499",
    "v": 28
  },
  "action": {
    "type": "borrowLend",
    "operation": "supply",
    "token": 0,
    "amount": null
  },
  "nonce": 1768147177757,
  "expiresAfter": 1768147188937
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xf26a7955ad543bb5f3e4043326516a0201e3003b48575a88963324a86c5815a0)

## Field Reference

### Action Fields

| Field       | Type   | Description                                                      |
| ----------- | ------ | ---------------------------------------------------------------- |
| `type`      | string | Always `"borrowLend"`                                            |
| `operation` | string | Operation type: `"deposit"`, `"withdraw"`, `"borrow"`, `"repay"` |
| `token`     | number | Token index                                                      |
| `amount`    | string | Amount                                                           |

## Use Cases

### Lending Activity Tracking

Monitor lending operations:

```python
def process_borrowLend_action(action):
    operation = action.get('operation')
    amount = action.get('amount')
    print(f"Lending: {operation} {amount}")
```

---

## cancel payload - Order Cancellations by ID

# cancel payload - Order Cancellations by ID

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `cancel` payload records one or more native Hyperliquid order-cancellation requests identified by order ID (`oid`).

## Sample Data

```json
{
  "signature": {
    "r": "0xb7233b2b2b0cf0eb161f86319be9a86c197f860dbcbe4d4f189e5fa757137c89",
    "s": "0x65e5d0ffd58b0bf7ed168a8d1a9b6f8df6050c7acf24db588fb62f9390e9a2c3",
    "v": 27
  },
  "action": {
    "type": "cancel",
    "cancels": [
      {
        "a": 0,
        "o": 291379970288
      }
    ]
  },
  "nonce": 1768146913376
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x13ca4a9463509042154404332645010202100079fe53af14b792f5e722546a2c)

## Field Reference

### Action Fields

| Field     | Type   | Description              |
| --------- | ------ | ------------------------ |
| `type`    | string | Always `"cancel"`        |
| `cancels` | array  | Array of cancel requests |

### Cancel Object Fields

| Field | Type   | Description                        |
| ----- | ------ | ---------------------------------- |
| `a`   | number | Asset index of the order to cancel |
| `o`   | number | Order ID (oid) to cancel           |

### Optional Fields

| Field          | Type   | Description                              |
| -------------- | ------ | ---------------------------------------- |
| `vaultAddress` | string | Vault address if cancelling vault orders |

## Use Cases

### Order Management Systems

Track cancellation activity to understand order lifecycle and fill rates:

```python
def process_cancel_action(action):
    for cancel in action.get('cancels', []):
        asset = cancel['a']
        order_id = cancel['o']

        print(f"Order cancelled: asset={asset}, oid={order_id}")
```

### Risk Management

Monitor cancellation patterns to detect:

- High cancellation rates (potential spoofing)
- Emergency position exits
- Market maker quote updates

### Market Making Analytics

Analyze the ratio of order placements to cancellations to understand market maker behavior and quote refresh rates.

## Related Action Payloads

- [order](https://www.dwellir.com/docs/hyperliquid/order) - New order payloads
- [cancelByCloid](https://www.dwellir.com/docs/hyperliquid/cancelByCloid) - Cancellations by client order ID
- [scheduleCancel](https://www.dwellir.com/docs/hyperliquid/scheduleCancel) - Scheduled cancellations

---

## cancelByCloid payload - Cancellations by Client ID

# cancelByCloid payload - Cancellations by Client ID

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `cancelByCloid` payload records native order-cancellation requests identified by client-assigned order ID (`cloid`).

## Sample Data

```json
{
  "signature": {
    "r": "0x2a0b6667955f197d530797576107b663fa08b20397286076f1684b3112738588",
    "s": "0x91a7dee6fae7c212e7b3f3a6dfbec5c555ac13986c56ec39bdc361b1713b8fb",
    "v": 28
  },
  "action": {
    "type": "cancelByCloid",
    "cancels": [
      {
        "asset": 159,
        "cloid": "0x00000000000007550096147985161351"
      },
      {
        "asset": 1,
        "cloid": "0x00000000000007580071223980263264"
      },
      {
        "asset": 5,
        "cloid": "0x00000000000007580071644980263273"
      }
    ]
  },
  "nonce": 1768146912996,
  "vaultAddress": "0x621c5551678189b9a6c94d929924c225ff1d63ab"
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x7aceda261c7a7d097c4804332644dc0202eb000bb77d9bdb1e978578db7e56f4)

## Field Reference

### Action Fields

| Field     | Type   | Description              |
| --------- | ------ | ------------------------ |
| `type`    | string | Always `"cancelByCloid"` |
| `cancels` | array  | Array of cancel requests |

### Cancel Object Fields

| Field   | Type   | Description                                                 |
| ------- | ------ | ----------------------------------------------------------- |
| `asset` | number | Asset index of the order to cancel                          |
| `cloid` | string | Client order ID (hex string) assigned when order was placed |

### Optional Fields

| Field          | Type   | Description                                      |
| -------------- | ------ | ------------------------------------------------ |
| `vaultAddress` | string | Vault address if cancelling vault orders         |
| `expiresAfter` | number | Timestamp after which the cancel request expires |

## Client Order ID Format

Client order IDs are 16-byte hex strings that you assign when placing orders. A common pattern encodes:

- Date/timestamp information
- Sequential counter
- System identifier

Example: `0x20260109000000000000000000150997`

- `20260109` - Date encoding (2026-01-09)
- `150997` - Sequence number

## Use Cases

### Trading System Integration

Use cloids to maintain order state without querying the exchange:

```python
def process_cancelByCloid_action(action):
    for cancel in action.get('cancels', []):
        asset = cancel['asset']
        cloid = cancel['cloid']

        # Match against your order management system
        order = order_tracker.get_by_cloid(cloid)
        if order:
            order.mark_cancelled()
```

### Order Lifecycle Tracking

Track orders from submission to cancellation using consistent identifiers across your systems.

### Latency Analysis

Compare timestamps between cancel request and block inclusion to measure execution latency.

## Related Action Payloads

- [order](https://www.dwellir.com/docs/hyperliquid/order) - Order payloads with client IDs
- [cancel](https://www.dwellir.com/docs/hyperliquid/cancel) - Cancellations by exchange order ID
- [modify](https://www.dwellir.com/docs/hyperliquid/modify) - Order modifications

---

## cDeposit payload - Staking Deposits

# cDeposit payload - Staking Deposits

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `cDeposit` payload records native tokens moving from a user's spot account into staking for delegation to validators.

## How to Read It

The action body gives you the raw native-token amount in `wei`. The surrounding signed-action envelope carries the signature and nonce, while the paired `resps.Full` entry tells you whether the staking transfer succeeded on chain.

## Sample Data

```json
{
  "signature": {
    "r": "0x3cbb47f1325d3c32177e669cd16b34c284382c9f14baaa6aab8378c2fd5f8a6",
    "s": "0x36c7707a539f353132f68255a1f96defb18fcc946af9e5fbb065104c0e537d6d",
    "v": 28
  },
  "action": {
    "type": "cDeposit",
    "signatureChainId": "0xa4b1",
    "hyperliquidChain": "Mainnet",
    "wei": 783683,
    "nonce": 1768148050528
  },
  "nonce": 1768148050528
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xb3f882d51bab1525b5720433267c0b02022b00bab6ae33f757c12e27daaeef10)

## Field Reference

### Envelope Fields

| Field       | Type   | Description                                              |
| ----------- | ------ | -------------------------------------------------------- |
| `signature` | object | ECDSA signature for the signed action                    |
| `nonce`     | number | Replay-protection nonce used for ordering and uniqueness |

### Action Fields

| Field              | Type   | Description                                              |
| ------------------ | ------ | -------------------------------------------------------- |
| `type`             | string | Always `"cDeposit"`                                      |
| `signatureChainId` | string | Chain identifier used during signing                     |
| `hyperliquidChain` | string | Target Hyperliquid environment, such as `Mainnet`        |
| `wei`              | number | Raw native-token amount transferred into staking, in wei |

## Processing Guidance

- Treat `wei` as a raw integer amount. Convert it with the asset metadata your application already trusts before rendering it to users.
- Do not mark the staking deposit as successful from the action payload alone. Join the action to its response in `resps.Full` and confirm the response status.
- Keep the nonce when indexing. It is useful for deduplication, timeline ordering, and replay protection analysis.
- Pair `cDeposit` with later [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) payloads when reconstructing a user's staking activity.

## Common Use Cases

### Staking Funding Monitoring

Track native tokens moving from spot balances into staking before validator delegation.

### Delegation Timeline Analysis

Combine staking deposits with later delegation payloads to reconstruct changes in staked balances.

## Related Action Payloads

- [cWithdraw](https://www.dwellir.com/docs/hyperliquid/cWithdraw) for transfers from staking back to spot
- [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) for validator delegation changes
- [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) for block and response pairing

---

## claimRewards payload - Reward Claims

# claimRewards payload - Reward Claims

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `claimRewards` payload records a request to claim accumulated trading, staking, or referral rewards.

## Sample Data

```json
{
  "signature": {
    "r": "0x8dedb7dedab58dacf6e8ce112dc72c73ea20ea9ab5a183d2e4b6447be7f8ae85",
    "s": "0x45e1720d57401d213f32f37af54718429f6e536aa93e6bd7a411fcc57cdf7c64",
    "v": 28
  },
  "action": {
    "type": "claimRewards"
  },
  "nonce": 1767950334968,
  "expiresAfter": 1767950346788
}
```

## Field Reference

### Action Fields

| Field  | Type   | Description             |
| ------ | ------ | ----------------------- |
| `type` | string | Always `"claimRewards"` |

## Use Cases

### Reward Claiming Activity

Track reward claims:

```python
def process_claimRewards_action(action):
    print("Rewards claimed")
```

## Related Action Payloads

- [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) - Token delegation for rewards
- [setReferrer](https://www.dwellir.com/docs/hyperliquid/setReferrer) - Referral relationships

---

## clearinghouseState - HyperCore Info Endpoint

# clearinghouseState - HyperCore Info Endpoint

Get comprehensive account state for perpetual trading, including margin summary, open positions, unrealized PnL, and liquidation prices.

The live response includes top-level `withdrawable`, `crossMaintenanceMarginUsed`, and `time` fields alongside `marginSummary` and `assetPositions`.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `clearinghouseState` endpoint is essential for derivatives traders, portfolio managers, and trading platforms who need to:

- **Monitor Account Health** — Track account value, margin usage, and withdrawable balance
- **Risk Management** — Monitor liquidation prices and position exposure
- **Portfolio Analytics** — Calculate unrealized PnL across all positions
- **Trading Bots** — Make automated trading decisions based on account state

## Request Parameters

- `type` (`string, required`): parameter: Must be `"clearinghouseState"`
- `user` (`string, required`): parameter: User's Ethereum wallet address
- `dex` (`string, optional`): parameter: HIP-3 market identifier (e.g., `"xyz"`). Omit to query the main Hyperliquid DEX, or use `"ALL_DEXES"` to fetch the main DEX plus all operational HIP-3 DEXs in one request.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "clearinghouseState",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `withdrawable` (`string, required`): Amount available for withdrawal
- `crossMaintenanceMarginUsed` (`string, required`): Maintenance margin currently reserved for cross positions
- `time` (`number, required`): Snapshot timestamp in milliseconds
- `marginSummary` (`object, required`): Overall margin information
- `crossMarginSummary` (`object, required`): Cross-margin specific summary
- `assetPositions` (`array, required`): List of open positions with details

## Successful Response

```json
{
  "withdrawable": "8000.50",
  "crossMaintenanceMarginUsed": "2000.00",
  "time": 1736443872382,
  "marginSummary": {
    "accountValue": "10000.50",
    "totalNtlPos": "5000.25",
    "totalRawUsd": "10000.00",
    "totalMarginUsed": "2000.00"
  },
  "crossMarginSummary": {
    "accountValue": "10000.50",
    "totalNtlPos": "5000.25",
    "totalRawUsd": "10000.00"
  },
  "assetPositions": [
    {
      "position": {
        "coin": "BTC",
        "szi": "0.5",
        "leverage": {
          "type": "cross",
          "value": 5
        },
        "entryPx": "40000.00",
        "positionValue": "20000.00",
        "unrealizedPnl": "500.00",
        "liquidationPx": "35000.00"
      }
    }
  ]
}
```

## The `dex` Parameter

By default, `clearinghouseState` returns state for the main Hyperliquid perpetuals DEX. To query a specific HIP-3 (permissionless perpetuals) market instead, include the `dex` field:

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "clearinghouseState",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f",
  "dex": "xyz"
}'
```

| `dex` value   | Returns                                                            |
| ------------- | ------------------------------------------------------------------ |
| *(omitted)*   | Main Hyperliquid perpetuals DEX                                    |
| `"xyz"`       | State for the specified HIP-3 market                               |
| `"ALL_DEXES"` | State for the main Hyperliquid DEX plus all operational HIP-3 DEXs |

Use `dex: "ALL_DEXES"` to fan out a single-user `clearinghouseState` request across the native DEX and every operational HIP-3 DEX. The response shape changes from a single state object to an object keyed by DEX name.

### `ALL_DEXES` Request

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "clearinghouseState",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f",
  "dex": "ALL_DEXES"
}'
```

### `ALL_DEXES` Response Shape

When `dex` is set to `"ALL_DEXES"`, the response becomes a DEX map instead of a single clearinghouse state:

```json
{
  "native": {
    "marginSummary": {
      "accountValue": "555.13644",
      "totalMarginUsed": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "555.13644"
    },
    "crossMarginSummary": {
      "accountValue": "555.13644",
      "totalMarginUsed": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "555.13644"
    },
    "crossMaintenanceMarginUsed": "0.0",
    "withdrawable": "555.13644",
    "assetPositions": [],
    "time": 1776448114549
  },
  "xyz": {
    "marginSummary": {
      "accountValue": "0.0",
      "totalMarginUsed": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "0.0"
    },
    "crossMarginSummary": {
      "accountValue": "0.0",
      "totalMarginUsed": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "0.0"
    },
    "crossMaintenanceMarginUsed": "0.0",
    "withdrawable": "0.0",
    "assetPositions": [],
    "time": 1776448114649
  }
}
```

The native DEX always appears under the `"native"` key. Additional keys correspond to operational HIP-3 DEX names from [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs).

## Common Use Cases

### 1. Check Account Health

Monitor account health and margin utilization:

```javascript
async function checkAccountHealth(userAddress) {
  const state = await getClearinghouseState(userAddress);
  const margin = state.marginSummary;

  const marginUsed = parseFloat(margin.totalMarginUsed);
  const accountValue = parseFloat(margin.accountValue);
  const utilizationRate = (marginUsed / accountValue) * 100;

  return {
    healthy: utilizationRate < 80,
    utilizationRate: utilizationRate.toFixed(2),
    accountValue: accountValue,
    marginUsed: marginUsed,
    withdrawable: parseFloat(state.withdrawable)
  };
}

// Usage
const health = await checkAccountHealth('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
if (!health.healthy) {
  console.warn(`High margin usage: ${health.utilizationRate}%`);
}
```

### 2. Monitor Liquidation Risk

Track liquidation prices for all positions:

```javascript
async function getLiquidationRisks(userAddress, currentPrices) {
  const state = await getClearinghouseState(userAddress);

  return state.assetPositions.map(pos => {
    const position = pos.position;
    const currentPrice = currentPrices[position.coin];
    const liquidationPrice = parseFloat(position.liquidationPx);
    const isLong = parseFloat(position.szi) > 0;

    const distance = isLong
      ? ((currentPrice - liquidationPrice) / currentPrice) * 100
      : ((liquidationPrice - currentPrice) / currentPrice) * 100;

    return {
      coin: position.coin,
      side: isLong ? 'LONG' : 'SHORT',
      currentPrice: currentPrice,
      liquidationPrice: liquidationPrice,
      distancePercent: distance.toFixed(2),
      risk: distance < 10 ? 'HIGH' : distance < 25 ? 'MEDIUM' : 'LOW'
    };
  });
}
```

### 3. Calculate Portfolio Metrics

Compute portfolio-wide metrics:

```javascript
async function getPortfolioMetrics(userAddress) {
  const state = await getClearinghouseState(userAddress);

  const totalPnl = state.assetPositions.reduce((sum, pos) => {
    return sum + parseFloat(pos.position.unrealizedPnl);
  }, 0);

  const totalPositionValue = state.assetPositions.reduce((sum, pos) => {
    return sum + parseFloat(pos.position.positionValue);
  }, 0);

  const accountValue = parseFloat(state.marginSummary.accountValue);
  const pnlPercent = (totalPnl / accountValue) * 100;

  return {
    accountValue: accountValue,
    totalPnl: totalPnl,
    pnlPercent: pnlPercent.toFixed(2),
    positionCount: state.assetPositions.length,
    totalPositionValue: totalPositionValue,
    leverage: (totalPositionValue / accountValue).toFixed(2)
  };
}
```

### 4. Position Summary Report

Generate a detailed position summary:

```javascript
async function getPositionSummary(userAddress) {
  const state = await getClearinghouseState(userAddress);

  console.log('\n=== Account Summary ===');
  console.log(`Account Value: $${state.marginSummary.accountValue}`);
  console.log(`Margin Used: $${state.marginSummary.totalMarginUsed}`);
  console.log(`Withdrawable: $${state.withdrawable}`);

  console.log('\n=== Open Positions ===');
  state.assetPositions.forEach(pos => {
    const p = pos.position;
    const side = parseFloat(p.szi) > 0 ? 'LONG' : 'SHORT';
    const size = Math.abs(parseFloat(p.szi));

    console.log(`\n${p.coin} ${side}`);
    console.log(`  Size: ${size}`);
    console.log(`  Entry Price: $${p.entryPx}`);
    console.log(`  Position Value: $${p.positionValue}`);
    console.log(`  Unrealized PnL: $${p.unrealizedPnl}`);
    console.log(`  Liquidation Price: $${p.liquidationPx}`);
    console.log(`  Leverage: ${p.leverage.value}x (${p.leverage.type})`);
  });
}
```

## Best Practices

1. **Poll responsibly** — Don't poll more frequently than needed (every 5-10 seconds is usually sufficient)
2. **Handle empty positions** — Account may have no open positions
3. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
4. **Monitor liquidation risk** — Set alerts when positions approach liquidation
5. **Cache when appropriate** — Cache data briefly to reduce API calls for dashboards

## Related Endpoints

- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get user's open orders
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user fee rates and volume
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot trading account state
- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state) — Get perp state, spot balances, and user abstraction in one request
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata for validation

***

*Access real-time Hyperliquid account state with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## convertToMultiSigUser payload - Multi-Sig Conversion

# convertToMultiSigUser payload - Multi-Sig Conversion

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `convertToMultiSigUser` payload records conversion of a single-signer account into a multi-signature account.

## Sample Data

```json
{
  "signature": {
    "r": "0xa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
    "s": "0x6543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba987",
    "v": 28
  },
  "action": {
    "type": "convertToMultiSigUser",
    "signers": [
      "0x1234567890abcdef1234567890abcdef12345678",
      "0xabcdef1234567890abcdef1234567890abcdef12"
    ],
    "threshold": 2
  },
  "nonce": 1767949700000
}
```

## Field Reference

### Action Fields

| Field       | Type   | Description                      |
| ----------- | ------ | -------------------------------- |
| `type`      | string | Always `"convertToMultiSigUser"` |
| `signers`   | array  | Addresses of authorized signers  |
| `threshold` | number | Required number of signatures    |

## Use Cases

### Security Upgrade Tracking

Monitor multi-sig conversions:

```python
def process_convertToMultiSigUser_action(action):
    signers = action.get('signers', [])
    threshold = action.get('threshold')
    print(f"Multi-sig created: {threshold}/{len(signers)} required")
```

## Related Action Payloads

- [multiSig](https://www.dwellir.com/docs/hyperliquid/multiSig) - Multi-signature operations

---

## createSubAccount payload - Sub-Account Creation

# createSubAccount payload - Sub-Account Creation

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `createSubAccount` payload records creation of a sub-account under a Hyperliquid master account.

## Sample Data

```json
{
  "signature": {
    "r": "0xb1e85a19894f08da2be6a3fc59c165daf03aeb90619211ea6eb94c38de6f4189",
    "s": "0x5d698bf033beb7efb63c29fb95cfbd9c1e7226841f365efe415ee35f60c028f",
    "v": 28
  },
  "action": {
    "type": "createSubAccount",
    "name": "test"
  },
  "nonce": 1768146918353
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x33b81eb4aa36b7b93531043326450502039a009a4539d68bd780ca07693a91a3)

## Field Reference

### Action Fields

| Field  | Type   | Description                             |
| ------ | ------ | --------------------------------------- |
| `type` | string | Always `"createSubAccount"`             |
| `name` | string | Human-readable name for the sub-account |

## Sub-Account Benefits

- **Risk Isolation**: Each sub-account has separate margin and positions
- **Strategy Separation**: Run different strategies without interference
- **API Wallet Support**: Agent wallets can trade on sub-accounts
- **Clean Accounting**: Easier PnL tracking per strategy

## Use Cases

### Account Structure Analysis

Track sub-account creation patterns:

```python
def process_createSubAccount_action(action):
    name = action.get('name')
    print(f"New sub-account created: {name}")
```

### User Sophistication Metrics

Sub-account creation indicates more sophisticated traders who segment their capital.

### Platform Growth Tracking

Monitor sub-account creation as a metric of platform engagement.

## Related Action Payloads

- [subAccountTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountTransfer) - Sub-account funding transfers
- [subAccountModify](https://www.dwellir.com/docs/hyperliquid/subAccountModify) - Sub-account setting changes
- [subAccountSpotTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountSpotTransfer) - Spot asset transfers

---

## createVault payload - Trading Vault Creation

# createVault payload - Trading Vault Creation

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `createVault` payload records creation of a managed Hyperliquid trading vault.

## Sample Data

```json
{
  "signature": {
    "r": "0x888843b89133ec3eaf8d81601a680a56fe026232233760e741e886269d6d47e4",
    "s": "0x26b3a835ef519f69ad117a4050658157bf9d4a6c253985b91f20c074c648ea62",
    "v": 28
  },
  "action": {
    "type": "createVault",
    "name": "TradingFXVPS",
    "description": "Traders seeking alpha beyond buy-and-hold crypto...",
    "initialUsd": 4999000000,
    "nonce": 1768149497821
  },
  "nonce": 1768149497821,
  "expiresAfter": 1768149511760
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x16947d46be525853180e043326c24e0201ff002c59557725ba5d28997d56323d)

## Field Reference

### Action Fields

| Field         | Type   | Description                                                  |
| ------------- | ------ | ------------------------------------------------------------ |
| `type`        | string | Always `"createVault"`                                       |
| `name`        | string | Display name for the vault                                   |
| `description` | string | Vault description (supports markdown/text)                   |
| `initialUsd`  | number | Initial USD deposit in atomic units (divide by 10^6 for USD) |
| `nonce`       | number | Transaction nonce for replay protection                      |

### Optional Fields

| Field          | Type   | Description                              |
| -------------- | ------ | ---------------------------------------- |
| `expiresAfter` | number | Timestamp after which the action expires |

## Amount Conversion

The `initialUsd` field is in atomic units:

- `4999000000` atomic units = $4,999.00 USD (divide by 10^6)

## Use Cases

### Vault Analytics

Track vault creation activity:

```python
def process_createVault_action(action):
    name = action.get('name')
    initial_usd = action.get('initialUsd', 0)
    initial_usd_display = initial_usd / 1_000_000

    print(f"New vault created: {name}")
    print(f"Initial deposit: ${initial_usd_display:,.2f}")
```

### Strategy Monitoring

Identify new trading strategies being launched on the platform.

### Ecosystem Growth Analysis

Track vault creation trends to measure platform adoption.

## Related Action Payloads

- [vaultTransfer](https://www.dwellir.com/docs/hyperliquid/vaultTransfer) - Vault deposits and withdrawals
- [NetChildVaultPositionsAction](https://www.dwellir.com/docs/hyperliquid/NetChildVaultPositionsAction) - Net child vault positions

---

## cWithdraw payload - Staking Withdrawals

# cWithdraw payload - Staking Withdrawals

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `cWithdraw` payload records native tokens moving from staking into the user's spot account through the 7-day unstaking queue.

## How to Read It

The action body contains the raw native-token amount and chain-scoping fields used during signing. The execution result arrives separately through the matching `resps.Full` entry, so indexers should pair the action and response before labeling the unstaking request as accepted.

## Sample Data

```json
{
  "signature": {
    "r": "0x8c864d08b6486f6c043c8359797175b14e2b3c6d61a82ceee9bc9cf2659a4be8",
    "s": "0x15835b21b87a1c0b55af90bda8f830aa128514b08960fcf757fd983be93cb128",
    "v": 27
  },
  "action": {
    "type": "cWithdraw",
    "signatureChainId": "0xa4b1",
    "hyperliquidChain": "Mainnet",
    "wei": 408761850,
    "nonce": 1768148277854
  },
  "nonce": 1768148277854
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xb0468b0b9072c7dbb1c004332686e402040300f12b75e6ad540f365e4f76a1c6)

## Field Reference

### Envelope Fields

| Field       | Type   | Description                                              |
| ----------- | ------ | -------------------------------------------------------- |
| `signature` | object | ECDSA signature for the signed action                    |
| `nonce`     | number | Replay-protection nonce used for ordering and uniqueness |

### Action Fields

| Field              | Type   | Description                                                           |
| ------------------ | ------ | --------------------------------------------------------------------- |
| `type`             | string | Always `"cWithdraw"`                                                  |
| `signatureChainId` | string | Chain identifier used during signing                                  |
| `hyperliquidChain` | string | Target Hyperliquid environment, such as `Mainnet`                     |
| `wei`              | number | Raw native-token amount requested for withdrawal from staking, in wei |

## Processing Guidance

- `wei` is not a user-ready decimal string. Convert it with the asset metadata your application already maintains.
- Join the action to the paired response before alerting on an unstaking request. A signed action appearing in the block stream is not the same as an accepted state change.
- Account for Hyperliquid's 7-day unstaking queue before treating the native tokens as available in the spot account.
- Interpret `cWithdraw` together with [cDeposit](https://www.dwellir.com/docs/hyperliquid/cDeposit) and [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) when reconstructing staking account state.

## Common Use Cases

### Unstaking Queue Monitoring

Track accepted withdrawal requests and the delay before native tokens return to spot balances.

### Staking Position Analysis

Correlate withdrawals with earlier deposits and delegation changes to reconstruct staking flows.

## Related Action Payloads

- [cDeposit](https://www.dwellir.com/docs/hyperliquid/cDeposit) for transfers from spot into staking
- [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) for validator delegation changes
- [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) for block and response pairing

---

## Hyperliquid Data Catalog

# Hyperliquid Data Catalog

This catalog maps what a Hyperliquid node writes to disk to the live and generated views exposed through Dwellir. Dataset and view names link to focused explainers with access paths, payload samples, file layouts, and field notes.

## Node-written data

These are raw protocol records emitted to files by a Hyperliquid node. Live and retained gRPC availability varies by feed; the S3 Bucket is the access path for archival files.

| Node source                                                                                | Purpose                                                                       | Live access                                                                                                                                       | Archival data                                                                                                                                                                   |
| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`replica_cmds`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks)                         | Hyperliquid blocks, signed actions, responses, and consensus metadata         | [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks), [GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block)                                                          | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2025-01-25` to today                                                                                                       |
| [`node_fills_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                   | Per-account execution records grouped by sequential block number              | [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills), [GetFills](https://www.dwellir.com/docs/hyperliquid/get_fills), [hl\_getBatchBlocks](https://www.dwellir.com/docs/hyperliquid/hl_getBatchBlocks) | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2025-07-27` to today; [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data); [indexed fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills) |
| [`node_order_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/order-statuses) | Order lifecycle events, including opens, fills, cancellations, and rejections | [StreamOrderStatuses](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses), [GetOrderStatuses](https://www.dwellir.com/docs/hyperliquid/get_order_statuses)                          | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-01-22` to today; [indexed order history](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/historical-orders)                 |
| [`node_raw_book_diffs_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/book-diffs)     | Native order-level additions, updates, and removals                           | [StreamRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs), [GetRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/get_raw_book_diffs)                            | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-01-22` to today                                                                                                       |
| [`misc_events_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/misc-events)            | Miscellaneous protocol events                                                 | [StreamMiscEvents](https://www.dwellir.com/docs/hyperliquid/stream_misc_events), [GetMiscEvents](https://www.dwellir.com/docs/hyperliquid/get_misc_events)                                      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-06-29` to today                                                                                                       |
| [`node_twap_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/twap-statuses)   | TWAP lifecycle events                                                         | [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses), [GetTwapStatuses](https://www.dwellir.com/docs/hyperliquid/get_twap_statuses)                              | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-07-01` to today                                                                                                       |
| [`periodic_abci_states`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/abci-states)            | Periodic RMP state dumps that can seed generated order-book snapshots         | [Dedicated Node Cluster gRPC](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster)                                                                        | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data) from `2026-04-14` to today                                                                                                       |

The node can also write `mempool_txs`: pre-consensus client blocks with signed transaction requests that are not guaranteed to land in a block. They are available live through [StreamMempoolTxs](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs) and [GetMempoolTxs](https://www.dwellir.com/docs/hyperliquid/get_mempool_txs) where the endpoint serves the feed, and are not part of the S3 Bucket.

### File families

- `replica_cmds` uses compressed JSONL chunks. A single file can contain multiple blocks; the [block explainer](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks) documents chunk names and line indexing.
- Most `*_by_block` feeds use a shared JSON envelope with one array of feed-specific events per sequential block number.
- `periodic_abci_states` uses binary MessagePack files (`.rmp` or `.rmp.lz4`). S3 provides archival access, while direct gRPC access requires a [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster).

### Shared `*_by_block` envelope

Most node-written `*_by_block` datasets store feed-specific events in the same envelope:

```json
{
  "local_time": "2026-07-02T11:10:49.483839100",
  "block_time": "2026-07-02T11:10:47.023075863",
  "block_number": 1057659853,
  "events": []
}
```

`local_time` is when the node wrote the record, `block_time` is the consensus timestamp, `block_number` is the sequential block position, and `events` contains dataset-specific values. An empty array means that source envelope has no matching events; it is not a transport heartbeat.

The sequential `block_number` in these envelopes and `abci_block.round` in `replica_cmds` are different values. Consensus rounds can skip and do not advance 1:1 with block height.

## S3 bucket coverage

The S3 bucket also contains older fill generations and generated order-book snapshots. See [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data) for formats and access details.

| Prefix                                                                                     | From         | To           | Object shape                  | Compressed size |  Files | Average/month | Files/month |
| ------------------------------------------------------------------------------------------ | ------------ | ------------ | ----------------------------- | --------------: | -----: | ------------: | ----------: |
| [`replica_cmds`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks)                         | `2025-01-25` | today        | LZ4-compressed native records |        80.65 TB | 68,993 |       4.99 TB |       3,766 |
| [`node_trades`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                           | `2025-03-22` | `2025-05-25` | `.lz4`                        |        15.13 GB |  1,541 |       6.73 GB |         720 |
| [`node_fills`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                            | `2025-05-25` | `2025-07-27` | `.lz4`                        |        31.81 GB |  1,507 |      13.49 GB |         720 |
| [`node_fills_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                   | `2025-07-27` | today        | `hourly .lz4`                 |       294.58 GB | 10,288 |      25.98 GB |         736 |
| [`node_order_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/order-statuses) | `2026-01-22` | today        | `hourly .lz4`                 |        18.56 TB |  6,000 |       2.19 TB |         736 |
| [`node_raw_book_diffs_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/book-diffs)     | `2026-01-22` | today        | `hourly .lz4`                 |         3.50 TB |  6,000 |     458.80 GB |         736 |
| [`misc_events_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/misc-events)            | `2026-06-29` | today        | `hourly .lz4`                 |        25.76 GB |  2,161 |       8.54 GB |         744 |
| [`node_twap_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/twap-statuses)   | `2026-07-01` | today        | `hourly .lz4`                 |         2.90 GB |  2,160 |       1.00 GB |         744 |
| [`orderbook_snapshots`](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots)             | `2026-04-14` | today        | `<height>.json.lz4`           |       283.03 GB | 19,115 |      56.01 GB |       3,765 |
| [`periodic_abci_states`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/abci-states)            | `2026-04-14` | today        | `<height>.rmp.lz4`            |        15.79 TB | 20,718 |       2.90 TB |       3,766 |

Sizes use decimal GB and TB. Monthly averages use up to three recent calendar months with files on every date.
Use the [date-range estimator](https://www.dwellir.com/docs/hyperliquid/historical-data#compressed-size-and-file-count) before buying access.

## Order books and derived data

V3 market streams expose typed live views without historical replay. Use the Hyperliquid Index or archival data when you need historical coverage.

| Derived view                                                                            | V3 market method                                                                                                                            | Related live or indexed access                                                                       |
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [L2 book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l2-book)                     | [StreamL2Book](https://www.dwellir.com/docs/hyperliquid/stream_l2_book)                                                                                            | [Order Book WebSocket L2](https://www.dwellir.com/docs/hyperliquid/l2-book)                                                 |
| [Best bid and offer](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/bbo)                        | [StreamBbo](https://www.dwellir.com/docs/hyperliquid/stream_bbo)                                                                                                   | [Order Book WebSocket BBO](https://www.dwellir.com/docs/hyperliquid/bbo)                                                    |
| [Ordered L2 book changes](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l2-book)               | [StreamL2BookDiff](https://www.dwellir.com/docs/hyperliquid/stream_l2_book_diff)                                                                                   | Seed from a known snapshot before applying diffs                                                     |
| [Full L4 order book](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book)                    | [StreamL4Book](https://www.dwellir.com/docs/hyperliquid/stream_l4_book)                                                                                            | [Order Book WebSocket L4](https://www.dwellir.com/docs/hyperliquid/l4-book)                                                 |
| [Typed L4 order updates](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book)                | [StreamL4OrderUpdates](https://www.dwellir.com/docs/hyperliquid/stream_l4_order_updates)                                                                           | [Order Book WebSocket overview](https://www.dwellir.com/docs/hyperliquid/order-book-server)                                 |
| Take-profit and stop-loss updates                                                       | [StreamTpslUpdates](https://www.dwellir.com/docs/hyperliquid/stream_tpsl_updates)                                                                                  | [Order Book WebSocket overview](https://www.dwellir.com/docs/hyperliquid/order-book-server)                                 |
| [Matched trades](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/trades)                         | [StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades)                                                                                             | [Order Book WebSocket trades](https://www.dwellir.com/docs/hyperliquid/trades) and [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data) |
| [All account fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)                  | [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills)                                                                                        | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/all-fills)                       |
| [Fills for one user](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)                 | [StreamUserFills](https://www.dwellir.com/docs/hyperliquid/stream_user_fills)                                                                                      | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                 |
| [Builder-attributed fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)           | [StreamBuilderFills](https://www.dwellir.com/docs/hyperliquid/stream_builder_fills)                                                                                | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                 |
| [Liquidation fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views)                  | [StreamLiquidationFills](https://www.dwellir.com/docs/hyperliquid/stream_liquidation_fills)                                                                        | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                 |
| [Live candles](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/candles)                          | [StreamCandle](https://www.dwellir.com/docs/hyperliquid/stream_candle)                                                                                             | Indexed [OHLCV history](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data)                              |
| [Generated order-book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots) | [StreamOrderbookSnapshots](https://www.dwellir.com/docs/hyperliquid/stream_orderbook_snapshots), [GetOrderbookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot) | [Order Book WebSocket L4](https://www.dwellir.com/docs/hyperliquid/l4-book)                                                 |
| [All market mids](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/market-context)                | [StreamAllMids](https://www.dwellir.com/docs/hyperliquid/stream_all_mids)                                                                                          | [Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint)                                                     |
| [Active asset context](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/market-context)           | [StreamActiveAssetCtx](https://www.dwellir.com/docs/hyperliquid/stream_active_asset_ctx)                                                                           | [Active asset data](https://www.dwellir.com/docs/hyperliquid/active-asset-data)                                             |

Order-book reconstruction requires a snapshot or another known state seed followed by ordered diffs. Raw diffs alone are insufficient. For trades, a match can contain multiple makers. Within one block, group fills by `(coin, tid)`. Across blocks, include `block_number` or `block_time` because `tid` is not globally unique.

## Practical guides

- [Connect to the Order Book WebSocket API](https://www.dwellir.com/guides/order-book-server) for a complete live L2/L4 integration walkthrough.
- [Track Hyperliquid whales](https://www.dwellir.com/guides/hyperliquid-whale-tracking) using fills, trades, and account data.
- [Monitor Hyperliquid funding rates](https://www.dwellir.com/guides/hyperliquid-funding-rates) with live and historical market data.
- [Export Hyperliquid OHLCV data to CSV](https://www.dwellir.com/guides/hyperliquid-ohlcv-csv-export) for analysis and backtesting.

---

## Hyperliquid BBO - Best Bid and Offer

# Hyperliquid BBO - Best Bid and Offer

BBO is the lowest-bandwidth order-book view. It reports the best bid and best ask for each requested market, including price, resting size, and order count at each top level.

## Access

| Availability | Access                                            | Details                                                                                                                                           |
| ------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live         | [StreamBbo](https://www.dwellir.com/docs/hyperliquid/stream_bbo)         | Provides typed V3 updates for up to 20 coins.                                                                                                     |
| Live         | [Order Book WebSocket BBO](https://www.dwellir.com/docs/hyperliquid/bbo) | Provides the live JSON `bbo` channel.                                                                                                             |
| Archival     | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)    | Historical top-of-book reconstruction requires a known snapshot or state seed followed by ordered book diffs; raw records alone are insufficient. |

## Live behavior

[StreamBbo](https://www.dwellir.com/docs/hyperliquid/stream_bbo) requires 1-20 coins after duplicate removal. It sends a typed initial current value for each requested coin, then sends another update only when that coin's top of book changes. `bid` or `ask` is unset when that side is empty, and ordering between different coins is unspecified.

BBO is a live view with no historical replay. Snapshot-style recovery can send the current value again after subscriber lag. If the RPC closes with `ABORTED`, reconnect to receive fresh current values.

## Sample data

This synthetic V3 protobuf payload visibly redacts the market identifier:

```protobuf
coin: "<redacted-market>"
time: 1785736814057
block_number: 1058646974
bid: { px: "114250.0" sz: "1.35" n: 4 }
ask: { px: "114251.0" sz: "0.82" n: 3 }
```

Treat each side as optional. An empty side is represented by an unset message field, not a zero-valued price level.

## Related pages

- [Order book WebSocket guide](https://www.dwellir.com/guides/order-book-server) — Build a resilient top-of-book and spread client.
- [L2 books](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l2-book) — Move from top-of-book prices to aggregated market depth.

---

## Hyperliquid Generated Order-Book Snapshots

# Hyperliquid Generated Order-Book Snapshots

`orderbook_snapshots` is generated data containing individual open orders across available markets at a point in time. It is separate from node-written feeds. Snapshot RPCs are intentionally absent from `ListFeeds` and use their own documented positioning rules.

## Access

| Availability  | Access                                                                                                                                         | Details                                                                                                           |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Live / replay | [StreamOrderbookSnapshots](https://www.dwellir.com/docs/hyperliquid/stream_orderbook_snapshots) and [GetOrderbookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot) | Stream generated snapshots from a timestamp or from the latest available record; retrieve one generated snapshot. |
| Live          | [Order Book WebSocket L4](https://www.dwellir.com/docs/hyperliquid/l4-book)                                                                                           | Live snapshot-plus-update alternative for a continuously maintained single-market book.                           |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                                                 | S3 coverage for `orderbook_snapshots`: `2026-04-14` to today, stored as `<height>.json.lz4`.                      |

## Snapshot behavior

[StreamOrderbookSnapshots](https://www.dwellir.com/docs/hyperliquid/stream_orderbook_snapshots) accepts an inclusive Unix-millisecond timestamp cursor. With no position, it sends the latest available snapshot immediately and then newer snapshots. A positioned stream begins with the snapshot covering the requested timestamp. [GetOrderbookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot) also returns the snapshot covering the requested timestamp; an empty request returns the latest available snapshot.

Snapshot availability and maximum response size vary by endpoint. A timestamp outside retained history returns `NOT_FOUND`, while an oversized response returns `RESOURCE_EXHAUSTED`. In V3, `block_number` and `timestamp` are transport cursors outside decoded `Record.data`. The bytes in `Record.data` decode directly to the snapshot's top-level array.

## Sample data

This synthetic decoded V3 `Record.data` payload visibly redacts the market and client-order identifiers. The numeric order ID is synthetic:

```json
[
  [
    "<redacted-market>",
    [
      [
        {
          "coin": "<redacted-market>",
          "side": "B",
          "limitPx": "114250.0",
          "sz": "0.40",
          "oid": 123456789,
          "timestamp": 1785736809123,
          "triggerCondition": "N/A",
          "isTrigger": false,
          "triggerPx": "0.0",
          "children": [],
          "isPositionTpsl": false,
          "reduceOnly": false,
          "orderType": "Limit",
          "origSz": "0.40",
          "tif": "Gtc",
          "cloid": "<redacted-client-order-id>"
        }
      ],
      []
    ]
  ]
]
```

Each top-level entry is `[coin, [bids, asks]]`. Individual order metadata can vary by order type.

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

Generated from 1 records in `orderbook_snapshots/20261021/1191310000.json.lz4` (2026-10-21).

```text
[]                               array
[][0]                            string
[][1]                            array
[][1][]                          array
[][1][][]                        object
  children                       array
  cloid                          null | string
  coin                           string
  isPositionTpsl                 bool
  isTrigger                      bool
  limitPx                        string
  oid                            number
  orderType                      string: Limit
  origSz                         string
  reduceOnly                     bool
  side                           string: A, B
  sz                             string
  tif                            string: Alo, Gtc
  timestamp                      number
  triggerCondition               string: N/A
  triggerPx                      string
[][]                             array | string
[][][]                           array
[][][][]                         object
  children                       array
  children[]                     object
    children                     array
    cloid                        null | string
    coin                         string
    isPositionTpsl               bool
    isTrigger                    bool
    limitPx                      string
    oid                          number
    orderType                    string: Stop Limit, Stop Market, Take Profit Limit, Take Profit Market
    origSz                       string
    reduceOnly                   bool
    side                         string: A, B
    sz                           string
    tif                          null
    timestamp                    number
    triggerCondition             string
    triggerPx                    string
  cloid                          null | string
  coin                           string
  isPositionTpsl                 bool
  isTrigger                      bool
  limitPx                        string
  oid                            number
  orderType                      string: Limit, Stop Limit, Stop Market, Take Profit Limit
  origSz                         string
  reduceOnly                     bool
  side                           string: A, B
  sz                             string
  tif                            null | string: Alo, Gtc
  timestamp                      number
  triggerCondition               string: N/A, Triggered
  triggerPx                      string
```

## Related pages

- [Order book WebSocket guide](https://www.dwellir.com/guides/order-book-server) — Implement snapshot handling, updates, and reconnection.
- [L4 books](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book) — Maintain the order-level live state represented by a snapshot.

---

## Hyperliquid Candles and OHLCV Data

# Hyperliquid Candles and OHLCV Data

Candles summarize executions into epoch-aligned open, high, low, close, volume, and trade-count buckets. Use them for charts, technical indicators, and time-bucketed activity analysis.

## Access

| Availability | Access                                                                                      | Details                                                                 |
| ------------ | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Live         | [StreamCandle](https://www.dwellir.com/docs/hyperliquid/stream_candle)                                             | Provides the current V3 OHLCV bucket.                                   |
| Historical   | [Hyperliquid Index OHLCV](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data)                   | Provides indexed history, ranges, live Index updates, and bulk exports. |
| Historical   | [Full-history exports](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/full-history-exports) | Provides CSV or Parquet files for selected markets.                     |

## V3 live candles

[StreamCandle](https://www.dwellir.com/docs/hyperliquid/stream_candle) subscribes to one coin and one interval. It supports exactly `1s`, `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, and `1d`.

The stream sends the current bucket immediately when one is available. Otherwise, its first frame arrives with the next execution. Buckets are sparse, so no execution means no frame. A newer `open_time` signals rollover, and another frame with the same `open_time` replaces the earlier state of that bucket.

V3 is live-only and has no historical replay. Its payload differs from Hyperliquid Index: V3 uses descriptive fields such as `open_time`, `close_time`, and `trade_count`, while Index responses use the compact `t`, `T`, and `n` schema and add indexed-product fields such as quote volume and finalization state.

## Sample data

This synthetic V3 protobuf payload visibly redacts the market identifier:

```protobuf
coin: "<redacted-market>"
interval: "1m"
open_time: 1785736800000
close_time: 1785736859999
open: "114200.0"
high: "114275.0"
low: "114180.0"
close: "114250.0"
volume: "12.75"
trade_count: 256
```

Each frame is a complete snapshot of one bucket, not a delta.

## Related pages

- [Export OHLCV to CSV](https://www.dwellir.com/guides/hyperliquid-ohlcv-csv-export) — Export one market or every discovered market to CSV.
- [Export OHLCV to Parquet](https://www.dwellir.com/guides/hyperliquid-ohlcv-parquet-export) — Create compressed columnar datasets for analytics.
- [Backfill the OHLCV archive](https://www.dwellir.com/guides/hyperliquid-ohlcv-archive-backfill) — Build a resumable full-history exporter.

---

## Hyperliquid Fill Views - All, User, Builder, Liquidation

# Hyperliquid Fill Views - All, User, Builder, Liquidation

V3 fill views expose one account's execution record per `Fill`. Records include position context, order identifiers, fees, and optional builder or liquidation metadata.

Within one block, fills from one match share `(coin, tid)`. Across blocks, include the frame's `block_number` in the match key.

Each participant remains a separate record. Retain account and order identity when deduplicating individual fills.

## Access

| Availability  | Access                                                                                                                                                                                                                                               | Details                                                           |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Live          | [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills), [StreamUserFills](https://www.dwellir.com/docs/hyperliquid/stream_user_fills), [StreamBuilderFills](https://www.dwellir.com/docs/hyperliquid/stream_builder_fills), and [StreamLiquidationFills](https://www.dwellir.com/docs/hyperliquid/stream_liquidation_fills) | Typed live fills and sequence validation.                         |
| Live / replay | [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills)                                                                                                                                                                                                        | Provides raw fill envelopes with cursor-based access.             |
| Historical    | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                                                                                                                                                                 | Provides all, user, builder, liquidation, and time-range history. |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                                                                                                                                                       | Provides archival fill files.                                     |

## Method family

| Method                                                               | Selection                                                                       |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills)                 | All fills, optionally scoped by coin and owning user.                           |
| [StreamUserFills](https://www.dwellir.com/docs/hyperliquid/stream_user_fills)               | Fills whose own `user` equals one required account.                             |
| [StreamBuilderFills](https://www.dwellir.com/docs/hyperliquid/stream_builder_fills)         | Fills attributed to one required `builder.address`.                             |
| [StreamLiquidationFills](https://www.dwellir.com/docs/hyperliquid/stream_liquidation_fills) | Fills carrying liquidation metadata, optionally filtered by liquidated account. |

All 4 methods are live-only with no historical replay. They use a per-subscription `sequence`; filtered blocks can still produce an empty `fills` list to preserve continuity. On a gap or `ABORTED`, reconnect for new live activity and recover the missing interval through a raw or indexed history surface.

## Sample data

This synthetic V3 protobuf payload visibly redacts account, transaction, builder, and client-order identifiers:

```protobuf
time: 1785736814057
block_number: 1058646974
sequence: 1
fills: {
  user: "<redacted-user>"
  coin: "<redacted-market>"
  px: "114250.0"
  sz: "0.25"
  side: "B"
  time: 1785736814057
  hash: "<redacted-transaction-hash>"
  tid: 99887766
  crossed: true
  dir: "Open Long"
  start_position: "0.0"
  oid: 123456789
  closed_pnl: "0.0"
  fee: "0.285625"
  fee_token: "USDC"
  builder: { address: "<redacted-builder>" fee: "0.01" }
  cloid: "<redacted-client-order-id>"
  liquidation: {
    liquidated_user: "<redacted-liquidated-user>"
    mark_px: "114200.0"
    method: "market"
  }
}
```

Optional nested messages are present only when they apply to the execution.

## Related pages

- [Whale tracking guide](https://www.dwellir.com/guides/hyperliquid-whale-tracking) — Combine attributed fills with order-book and account signals.
- [Matched trades](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/trades) — Use match-level executions when participant-specific records are unnecessary.

---

## Hyperliquid L2 Books - Snapshots and Diffs

# Hyperliquid L2 Books - Snapshots and Diffs

An L2 book groups resting liquidity by price. Each level contains price (`px`), total size (`sz`), and the number of resting orders (`n`), without exposing individual order identity.

## Access

| Availability | Access                                                                                                         | Details                                                                                                           |
| ------------ | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Live         | [StreamL2Book](https://www.dwellir.com/docs/hyperliquid/stream_l2_book) and [StreamL2BookDiff](https://www.dwellir.com/docs/hyperliquid/stream_l2_book_diff) | Provides typed replacement snapshots for one coin, plus opening snapshots and ordered changes for up to 20 coins. |
| Live         | [Order Book WebSocket L2](https://www.dwellir.com/docs/hyperliquid/l2-book)                                                           | Provides the live JSON `l2Book` channel.                                                                          |
| Archival     | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                 | Raw book records can support custom historical reconstruction when paired with a known state seed.                |

## Requests and depth

[StreamL2Book](https://www.dwellir.com/docs/hyperliquid/stream_l2_book) sends full snapshots for one coin. Omitted `n_levels` means 20 levels per side, values 1 through 100 select bounded depth, and explicit 0 requests full depth only when the endpoint supports it. An unsupported full-depth request returns `FAILED_PRECONDITION`.

For both full snapshots and [StreamL2BookDiff](https://www.dwellir.com/docs/hyperliquid/stream_l2_book_diff), `n_sig_figs` accepts 2, 3, 4, or 5. `mantissa` is valid only with `n_sig_figs` set to 5, and its value must be 2 or 5. `strict` is available only on `StreamL2Book` and suppresses unchanged snapshots.

## Reconstruction behavior

`StreamL2Book` opens with the current full book, then sends replacement snapshots. `StreamL2BookDiff` accepts 1-20 coins and opens with one `snapshot: true` full-book entry per coin. Use that snapshot as the state seed before you apply later diffs. Track `seq` and `prev_seq` independently per coin, remove a level when `sz` is `"0.0"`, and reconnect for new snapshot seeds after a gap or `ABORTED`.

Both streams are live views with no historical replay. A quiet coin can omit frames, and full-snapshot `block_number` values can skip when unchanged windows are coalesced.

## Sample data

This synthetic V3 opening payload visibly redacts the market identifier:

```protobuf
time: 1785736814057
block_number: 1058646974
diffs: {
  coin: "<redacted-market>"
  seq: 1
  prev_seq: 0
  bids: { px: "114250.0" sz: "1.35" n: 4 }
  asks: { px: "114251.0" sz: "0.82" n: 3 }
  snapshot: true
}
```

Later diff entries contain only changed levels. The complete bid and ask arrays appear again after a reconnect.

## Related pages

- [Order book WebSocket guide](https://www.dwellir.com/guides/order-book-server) — Build a production L2 client with reconnection handling.
- [Best bid and offer](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/bbo) — Use a lower-bandwidth top-of-book view.
- [L4 books](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book) — Inspect individual resting orders instead of aggregated levels.

---

## Hyperliquid L4 Books - Individual Orders

# Hyperliquid L4 Books - Individual Orders

An L4 book keeps each resting order distinct. Orders include owner, order ID, side, price, remaining size, placement time, order type, and optional client-order identity.

## Access

| Availability | Access                                                                                                                 | Details                                                                                 |
| ------------ | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| Live         | [StreamL4Book](https://www.dwellir.com/docs/hyperliquid/stream_l4_book) and [StreamL4OrderUpdates](https://www.dwellir.com/docs/hyperliquid/stream_l4_order_updates) | Provides the typed snapshot-or-diff oneof for one coin and decoded, sequenced changes.  |
| Live         | [Order Book WebSocket L4](https://www.dwellir.com/docs/hyperliquid/l4-book)                                                                   | Provides a JSON snapshot followed by order-level updates.                               |
| Archival     | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                         | Records can support custom historical reconstruction when seeded from a known snapshot. |

## V3 stream choices

[StreamL4Book](https://www.dwellir.com/docs/hyperliquid/stream_l4_book) serves one coin. Its typed `L4BookUpdate` oneof contains either an opening `snapshot` or a later `diff`. The snapshot contains typed orders. The diff carries the native `{order_statuses, book_diffs}` JSON bytes for that block.

[StreamL4OrderUpdates](https://www.dwellir.com/docs/hyperliquid/stream_l4_order_updates) is the decoded alternative. It opens with `snapshot: true`, then sends typed `NEW`, `UPDATE`, and `REMOVE` order changes. Its `sequence` begins at 1 and must remain contiguous. An empty `coins` list selects all coins, and `users` optionally filters order owners.

Both streams are live views with no historical replay. On `ABORTED`, reconnect and resnapshot. For typed order updates, a sequence gap also requires reconnecting and rebuilding from the next opening snapshot. Never continue from a partial order map after either condition.

## Sample data

This synthetic V3 typed-update payload visibly redacts the account and market identifiers:

```protobuf
time: 1785736814057
block_number: 1058646974
diffs: {
  diff_type: L4_ORDER_DIFF_TYPE_NEW
  coin: "<redacted-market>"
  oid: 123456789
  user: "<redacted-user>"
  side: "B"
  px: "114250.0"
  sz: "0.40"
}
snapshot: true
sequence: 1
```

An opening typed-update frame represents current resting state as `NEW` entries. Later frames apply changes in sequence order.

## Related pages

- [Order book WebSocket guide](https://www.dwellir.com/guides/order-book-server) — Build a production L4 client with snapshot and update handling.
- [Whale tracking guide](https://www.dwellir.com/guides/hyperliquid-whale-tracking) — Use individual resting orders as a whale signal.
- [Generated order-book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots) — Inspect the related order-level state seed.

---

## Hyperliquid Market Context - Mids and Asset Data

# Hyperliquid Market Context - Mids and Asset Data

The V3 market-context family provides current default-DEX perpetual-market values. `StreamAllMids` sends the complete mid-price map, while `StreamActiveAssetCtx` sends detailed context for one perp.

## Access

| Availability | Access                                                                                                                           | Details                                                                                                                                                         |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live         | [StreamAllMids](https://www.dwellir.com/docs/hyperliquid/stream_all_mids) and [StreamActiveAssetCtx](https://www.dwellir.com/docs/hyperliquid/stream_active_asset_ctx)         | Provides the current full perp mid map and current context for one perp.                                                                                        |
| Live         | [Info endpoint active asset data](https://www.dwellir.com/docs/hyperliquid/active-asset-data)                                                           | Request-response alternative for asset context.                                                                                                                 |
| Historical   | [Hyperliquid Index OHLCV](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data) and [fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills) | Provides candle and execution history only. It does not reproduce historical `ActiveAssetCtx` state or standalone funding, open-interest, or mid-price history. |

## Method family

[StreamAllMids](https://www.dwellir.com/docs/hyperliquid/stream_all_mids) takes an empty request. Each frame contains the complete map and supersedes the previous frame. A bookless market can use its last trade as the available midpoint value.

[StreamActiveAssetCtx](https://www.dwellir.com/docs/hyperliquid/stream_active_asset_ctx) requires one default-DEX perp coin. It reports funding, open interest, previous-day price, rolling volume, oracle and mark prices, and optional book-dependent fields. `premium` and `mid_px` can be unset, and `impact_pxs` can be empty, when no book is available.

Both are current-state streams with no historical replay. Their `time` is when the endpoint made the update available, not a block timestamp. Each frame replaces the prior state. Reconnect after `ABORTED`; `UNAVAILABLE` means fresh current data is not available.

## Sample data

These synthetic V3 protobuf payloads visibly redact the market identifier:

```protobuf
time: 1785736814057
mids: { key: "<redacted-market>" value: "114250.5" }
```

```protobuf
coin: "<redacted-market>"
time: 1785736814057
funding: "0.0000125"
open_interest: "19234.55"
prev_day_px: "112500.0"
day_ntl_vlm: "985000000.25"
premium: "0.00018"
oracle_px: "114230.0"
mark_px: "114250.0"
mid_px: "114250.5"
impact_pxs: "114249.0"
impact_pxs: "114252.0"
day_base_vlm: "8650.75"
```

Do not interpret the update time as execution time or block position.

## Related pages

- [Funding rates guide](https://www.dwellir.com/guides/hyperliquid-funding-rates) — Fetch and interpret current, predicted, and historical funding.
- [Whale tracking guide](https://www.dwellir.com/guides/hyperliquid-whale-tracking) — Combine current market context with fills, books, and account data.

---

## Hyperliquid Trades - Live Trade Prints

# Hyperliquid Trades - Live Trade Prints

Trades are normalized match records for tape displays, execution analytics, and market-flow signals. Each trade reports the taker side, execution price and size, transaction hash, match identifier, and every bid-side and ask-side participant.

## Access

| Availability | Access                                                               | Details                                                        |
| ------------ | -------------------------------------------------------------------- | -------------------------------------------------------------- |
| Live         | [StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades)                      | Provides typed V3 gRPC trade batches.                          |
| Live         | [Order Book WebSocket trades](https://www.dwellir.com/docs/hyperliquid/trades)              | Provides live JSON trade messages and an optional user filter. |
| Historical   | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills) | Provides a historical alternative.                             |
| Historical   | [Tick data](https://www.dwellir.com/docs/hyperliquid/tick-data)                             | Provides a historical alternative.                             |
| Archival     | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                       | Provides archival fill records for custom processing.          |

## Live behavior

[StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades) accepts 1-20 coins and an optional user filter. It batches matches by `(block, coin)`.

`bid_users` and `ask_users` are repeated fields because a match can contain multiple makers. A self-trade can place the same address on both sides.

Within one block, identify a match by `(coin, tid)`. Across blocks, include the batch's `block_number` in the match key.

The gRPC stream is live-only. It has no opening snapshot and no historical replay. `ABORTED` means frames were lost or live state reset. Reconnect for new activity, then use an archival or indexed alternative to recover any missed interval.

## Sample data

This synthetic V3 protobuf payload uses visible redaction markers instead of production identifiers:

```protobuf
time: 1785736814057
block_number: 1058646974
trades: {
  coin: "<redacted-market>"
  side: "B"
  px: "114250.0"
  sz: "0.75"
  hash: "<redacted-transaction-hash>"
  time: 1785736814057
  tid: 99887766
  bid_users: "<redacted-bid-user>"
  ask_users: "<redacted-ask-user>"
  ask_users: "<redacted-second-ask-user>"
  synthetic: false
}
```

The Order Book WebSocket represents the same participant set in a single `users` array. The V3 gRPC payload keeps bid-side and ask-side users separate.

## Related pages

- [Whale tracking guide](https://www.dwellir.com/guides/hyperliquid-whale-tracking) — Build real-time alerts around large, attributed trades.
- [Order book WebSocket guide](https://www.dwellir.com/guides/order-book-server) — Combine trades with L2, L4, and multi-coin routing.
- [Derived fill views](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views) — Move from match-level trades to participant-specific execution records.

---

## Hyperliquid Periodic ABCI State - Binary Data

# Hyperliquid Periodic ABCI State - Binary Data

`periodic_abci_states` contains periodic binary state dumps. These files are archival inputs for state-aware consumers and can seed generated order-book snapshots. They are not a JSON event feed.

## Access

| Availability      | Access                                                                                                                                         | Details                                                                                                                                      |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Live / replay     | [Dedicated Node Cluster gRPC](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster)                                                                     | Direct gRPC access to `periodic_abci_states` is available only with a [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster). |
| Archival          | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                                                 | S3 coverage for `periodic_abci_states`: `2026-04-14` to today, stored as `<height>.rmp.lz4`.                                                 |
| Related live data | [StreamOrderbookSnapshots](https://www.dwellir.com/docs/hyperliquid/stream_orderbook_snapshots) and [GetOrderBookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot) | Snapshot availability and maximum response size vary by endpoint.                                                                            |

## File layout

Depending on the source object and compression state, the relative filename ends in one of these forms:

```text
periodic_abci_states/<date>/<block-number>.rmp
periodic_abci_states/<date>/<block-number>.rmp.lz4
```

## Binary format

The payload is binary RMP (MessagePack) state. A `.rmp.lz4` object must be decompressed before an RMP decoder reads it; the resulting bytes are still RMP, not JSON. Select a decoder that matches the node-state schema for the object you consume. Never pass the bytes to a JSON parser or infer a JSON structure from the filename.

## Important fields

There is no stable top-level JSON field table for this dataset. The filename identifies the associated sequential block position, while the decoded binary fields depend on the matching RMP state schema. Preserve large integers, byte arrays, and map keys without lossy JSON conversion.

For order-book reconstruction, use a generated snapshot derived for that purpose and then apply ordered book diffs after its position. Do not treat an arbitrary binary state dump as the public snapshot response shape.

A generated book snapshot cannot establish complete account balances or margin state. See [account-risk reconstruction requirements](https://www.dwellir.com/docs/hyperliquid/research#can-i-reconstruct-account-risk-from-book-snapshots) before selecting replay inputs.

## Observed fields

Each line lists the keys inside one container. `[n]` after a key is the largest array length seen. `[]` marks an array element and `[1]` the value half of a key-value pair. The walk stops 7 levels deep. Field names follow the node-state schema and can change at a hardfork.

Generated from `periodic_abci_states/20261021/1191310000.rmp.lz4` (2026-10-21).

```text
(root): exchange
exchange: action_delayer, advt, agent_tracker, allowed_liquidators[5], app_hash_vote_tracker, begin_block_logic_guard, book_empty_user_states_pruning_guard, bridge2, c_staking, cancel_aggressive_orders_at_open_interest_cap_guard, default_hip3_limits, dex_abstraction_enabled, disabled_precompiles[0], evm_enabled, funding_distribute_guard, funding_err_dur_guard, funding_update_guard, hil, hip3_no_cross, hip3_stale_mark_px_guard, hlp_start_of_day_account_value, hyper_evm, hyperliquidity, initial_usdc_evm_system_balance, last_hlp_cancel_time, lhvt, locus, lvt, max_hlp_withdraw_fraction_per_day, max_order_distance_from_anchor, msc, multi_sig_tracker, oh[100], partial_liquidation_cooldown, perp_deploy_gas_auction, perp_dexs[11], pmi, pmn, post_only_until_height, post_only_until_time, prune_agent_idx, pt, pvs, register_token_gas_auction, reserve_accumulators[3], scheduled_freeze_height, spot_books[1121], spot_disabled, spot_pair_deploy_gas_auction, spot_twap_tracker, staking, staking_link_tracker, sub_account_tracker, user_to_display_name[3275], user_to_evm_state[1111429], user_to_evm_to_l1_wei_remaining[0], user_to_scheduled_cancel[265], validator_l1_stream_tracker, validator_l1_vote_tracker, vtg
exchange.action_delayer: delay_scale, delayed_actions[0], max_n_delayed_actions, n_total_delayed_actions, user_to_n_delayed_actions[0]
exchange.advt: adu, h, highest_quorum_height, htm[0], qrs[0], tracker
exchange.advt.h: l, q
exchange.advt.tracker: hsc, i[51], name
exchange.advt.tracker.hsc: i, q
exchange.advt.tracker.i[][1]: qst, vts[1]
exchange.agent_tracker: address_to_nonce_set[158663], agent_to_user[418223], user_to_extra_agents[292422], user_to_main_agent[73546], user_to_pending_agent_removals[0]
exchange.agent_tracker.user_to_extra_agents[][1][]: a, n, v
exchange.agent_tracker.user_to_main_agent[][1]: a, v
exchange.app_hash_vote_tracker: highest_quorum_height, quorum_app_hashes[0], tracker
exchange.app_hash_vote_tracker.tracker: hsc[0], i[26], name
exchange.app_hash_vote_tracker.tracker.i[][1]: qst, vts[1]
exchange.begin_block_logic_guard: bucket_millis, last_bucket
exchange.book_empty_user_states_pruning_guard: bucket_millis, last_bucket
exchange.bridge2: bal, dvp[0], dvpd, dvs[22], eth_id_to_deposit_votes, finished_deposits_data[9768], finished_withdrawal_to_time[10872], last_pruned_deposit_block_number, lfd, oaw, r, validator_set_finalized_votes, validator_set_signatures, withdrawal_finalized_votes, withdrawal_signatures
exchange.bridge2.dvs[][1]: ne, nv
exchange.bridge2.eth_id_to_deposit_votes: hsc, i[0], name
exchange.bridge2.eth_id_to_deposit_votes.hsc: i, q
exchange.bridge2.finished_deposits_data[][]: b, e, h, i, s, t, u
exchange.bridge2.finished_withdrawal_to_time[][]: n, u
exchange.bridge2.r: c
exchange.bridge2.r.c: a, i
exchange.bridge2.validator_set_finalized_votes: hsc[0], i[4], name
exchange.bridge2.validator_set_finalized_votes.i[][1]: qst, vts[1]
exchange.bridge2.validator_set_signatures: hsc[0], i[1], name
exchange.bridge2.validator_set_signatures.i[][1]: qst, vts[1]
exchange.bridge2.withdrawal_finalized_votes: hsc[0], i[0], name
exchange.bridge2.withdrawal_signatures: hsc[0], i[166], name
exchange.bridge2.withdrawal_signatures.i[][]: n, qst, u, vts[1]
exchange.c_staking: allow_all_validators, allowed_validators[16], broadcasters[9], delegations, disabled_node_ips[0], disabled_validators[0], distribute_reward_bucket_guard, gms, jail_until[0], jailed_signers, jvt, lsc, native_token_reserve, pending_withdrawals, proposals[0], retired_signers[0], self_delegation_requirement, signer_to_last_manual_unjail_time[0], stage_reward_bucket_guard, stakes, stakes_decay_bucket_guard, user_states[108951], validator_to_profile[35], validator_to_staged_rewards[27], validator_to_state[35], vms
exchange.c_staking.delegations: user_to_delegations[48799], validator_to_state[35]
exchange.c_staking.delegations.validator_to_state[][1]: delegator_to_epoch_delegation[1487], total_delegated
exchange.c_staking.distribute_reward_bucket_guard: bucket_millis, last_bucket
exchange.c_staking.jailed_signers: current[6], current_round, epoch_values, n_keep, period
exchange.c_staking.jailed_signers.epoch_values: initial_round, round_to_val[300]
exchange.c_staking.jvt: hsc[0], i[0], name
exchange.c_staking.pending_withdrawals: queue[772], user_to_total_withdrawal[682]
exchange.c_staking.pending_withdrawals.user_to_total_withdrawal[][1]: n, wei
exchange.c_staking.stage_reward_bucket_guard: bucket_millis, last_bucket
exchange.c_staking.stakes: current, current_round, epoch_values, n_keep, period
exchange.c_staking.stakes.current: hv[22], max_n_validators, validator_to_stake[35]
exchange.c_staking.stakes.epoch_values: initial_round, round_to_val[300]
exchange.c_staking.stakes_decay_bucket_guard: bucket_millis, last_bucket
exchange.c_staking.validator_to_profile[][1]: commission_bps, delegations_disabled, description, name, node_ip, signer
exchange.c_staking.validator_to_profile[][1].node_ip: Ip[4]
exchange.c_staking.validator_to_state[][1]: delegations_blocked, last_signer_change_time, register_time
exchange.cancel_aggressive_orders_at_open_interest_cap_guard: bucket_millis, last_bucket
exchange.default_hip3_limits: daily_px_range, max_n_users_with_positions, max_transfer_ntl2, max_under_initial_margin_transfer_ntl2, oi_sz_cap_per_perp, total_oi_cap2
exchange.funding_distribute_guard: bucket_millis, last_bucket
exchange.funding_err_dur_guard: err_duration, first_err_time, last_err_time
exchange.funding_update_guard: bucket_millis, last_bucket
exchange.hil: half_life, m, max_n_depositors, max_slippage
exchange.hip3_stale_mark_px_guard: bucket_millis, last_bucket
exchange.hyper_evm: big_block_context, disabled_core_writer_actions[0], ft[0], is_initialized, l1_to_evm_erc20_queue[1], l1_to_evm_native_token_queue[0], l1_transfers_enabled, latest_block2, mrb, put[0], small_block_context, state2, ub, ul
exchange.hyper_evm.big_block_context: bucket_guard, latest_block, mempool
exchange.hyper_evm.big_block_context.bucket_guard: bucket_millis, last_bucket
exchange.hyper_evm.big_block_context.latest_block: Reth115
exchange.hyper_evm.big_block_context.latest_block.Reth115: body, header
exchange.hyper_evm.big_block_context.latest_block.Reth115.body: ommers[0], transactions[2], withdrawals[0]
exchange.hyper_evm.big_block_context.latest_block.Reth115.header: hash, header
exchange.hyper_evm.big_block_context.mempool: address_to_txs[37], len
exchange.hyper_evm.l1_to_evm_erc20_queue[]: contract, send_to_evm_data, system_address, token, user, wei
exchange.hyper_evm.l1_to_evm_erc20_queue[].send_to_evm_data: data, destination_chain_id, destination_recipient, gas_limit, nonce
exchange.hyper_evm.latest_block2: Reth115
exchange.hyper_evm.latest_block2.Reth115: body, header
exchange.hyper_evm.latest_block2.Reth115.body: ommers[0], transactions[5], withdrawals[0]
exchange.hyper_evm.latest_block2.Reth115.header: hash, header
exchange.hyper_evm.latest_block2.Reth115.header.header: baseFeePerGas, blobGasUsed, difficulty, excessBlobGas, extraData, gasLimit, gasUsed, logsBloom, miner, mixHash, nonce, number, parentBeaconBlockRoot, parentHash, receiptsRoot, sha3Uncles, stateRoot, timestamp, transactionsRoot, withdrawalsRoot
exchange.hyper_evm.small_block_context: bucket_guard, latest_block, mempool
exchange.hyper_evm.small_block_context.bucket_guard: bucket_millis, last_bucket
exchange.hyper_evm.small_block_context.latest_block: Reth115
exchange.hyper_evm.small_block_context.latest_block.Reth115: body, header
exchange.hyper_evm.small_block_context.latest_block.Reth115.body: ommers[0], transactions[5], withdrawals[0]
exchange.hyper_evm.small_block_context.latest_block.Reth115.header: hash, header
exchange.hyper_evm.small_block_context.mempool: address_to_txs[1806], len
exchange.hyper_evm.state2: block_hashes[257], evm_db
exchange.hyper_evm.state2.evm_db: NoEvmDb
exchange.hyperliquidity: ensure_order_bucket_guard, spot_to_range[1091]
exchange.hyperliquidity.ensure_order_bucket_guard: bucket_millis, last_bucket
exchange.hyperliquidity.spot_to_range[][1]: order_sz, points[4000]
exchange.lhvt: adu, h, highest_quorum_height, htm[0], qrs[0], tracker
exchange.lhvt.h: l, q
exchange.lhvt.tracker: hsc, i[6], name
exchange.lhvt.tracker.hsc: i, q
exchange.lhvt.tracker.i[][1]: qst, vts[1]
exchange.locus: aux[0], blp, chn, cls[11], ctr, ctx, ftr, hcm, msc, pdl, pmu, qus[3], scl, uaR[0], uac[6663], ust[2799178], vlt[9478]
exchange.locus.blp: b, bog, bwo, dp, du, e, mbs, n, o, os, p, pma, pmdl, pml, pmmt, pmmu, pmv, r, u[22879], ubgl, ubul, uobc
exchange.locus.blp.b: e, er[4]
exchange.locus.blp.bog: bucket_millis, last_bucket
exchange.locus.blp.pmdl: m, n
exchange.locus.blp.pml: m, n
exchange.locus.blp.r: p, t[5], u
exchange.locus.blp.u[][1]: t[3]
exchange.locus.blp.ubgl: m, n
exchange.locus.blp.ubul: m, n
exchange.locus.blp.uobc: n, t
exchange.locus.cls[]: adl_shortfall_remaining, bridge2_withdraw_fee, daily_exchange_scaled_and_raw_vlms[21], halted_assets[56], isolated_external[0], isolated_oracle[1], last_set_global_time, lnsgt, max_withdraw_leverage, meta, moh, oracle, override_max_signed_distances_from_oracle[0], perform_auto_deleveraging, total_net_deposit, total_non_bridge_deposit, usdc_ntl_scale[2], user_states, znfn
exchange.locus.cls[].meta: collateralToken, collateralTokenName, marginTableIdToMarginTable[7], pdi, universe[234]
exchange.locus.cls[].moh: Hip3, Main
exchange.locus.cls[].moh.Hip3: df[127], hip3_backstop_liquidator_state, limits, schema, state
exchange.locus.cls[].moh.Main: asset_to_recent_oi[30], assets_at_open_interest_cap[7], override_max_oi_per_second[5], reset_recent_oi_bucket_guard
exchange.locus.cls[].oracle: err_dur_guard, lmpe[183], mpcg[0], msoe, pmep[1], pmpo[0], psro[2], pxs2[234], ror
exchange.locus.cls[].oracle.err_dur_guard: err_duration, first_err_time, last_err_time
exchange.locus.cls[].oracle.msoe: e[183], g
exchange.locus.cls[].oracle.ror: ktm[704], roc, utl[23]
exchange.locus.cls[].user_states: ar[1], asset_to_oi_szi[234], check_all_users_for_liquidatables, open_order_tracker, user_to_state[2349631], users_with_positions[105139]
exchange.locus.cls[].user_states.open_order_tracker: user_to_data[17663]
exchange.locus.ctr: ac, sc, so, tc, tn, to, vn
exchange.locus.ctr.ac: c, l, m, p
exchange.locus.ctr.ac.c: s
exchange.locus.ctx: hardfork, hardfork_height, height, mac, next_lid, next_oid, next_twap_id, prev_time, round, system_nonce, time, tx_index, use_system_nonce
exchange.locus.ctx.hardfork: round, version
exchange.locus.ftr: code_to_referrer[65611], collected_builder_fees[1949], fee_schedule, referral_bucket_millis, referrer_states[65611], total_fees_collected, total_spot_fees_collected, trials_disabled, unrewarded_users[13], user_states[2017108]
exchange.locus.ftr.fee_schedule: destination, extra_destination_fractions[1], rates[4], referral_discount, referrer_keep, stake_discount_tiers, tiers, weigh_spot_volume_double
exchange.locus.ftr.fee_schedule.stake_discount_tiers: tiers[6]
exchange.locus.ftr.fee_schedule.tiers: mm[3], vip[6]
exchange.locus.ftr.referrer_states[][1]: b, c, n, s[3]
exchange.locus.ftr.user_states[][1]: F, T[1], r
exchange.locus.msc: ape, apw, mts, nts, scri, tse, uts[217]
exchange.locus.scl: daily_exchange_scaled_and_raw_vlms[21], eebl, eec, evm_transfer_escrows[1254], meta, native_token, pmr[5], soh, spot_dusting_opted_out_users[4537], token_fees_collected[1045], token_to_genesis[1107], token_to_max_supply[1094], token_to_pending_evm_contract[0], user_states[2233076]
exchange.locus.scl.daily_exchange_scaled_and_raw_vlms[][1]: r, s
exchange.locus.scl.eebl: m, n
exchange.locus.scl.eec: n, t
exchange.locus.scl.meta: allow_duplicate_token_names, canonical_tokens2[2], dtl[2], liquid_base_tokens[7], liquid_quote_tokens[2], outr, quote_token_to_status[4], spot_infos[1121], ta2[1], token_id_to_token[1275], token_infos[1275], token_name_to_canonical_deployer[0], token_to_approx_usdc_pxs[11], token_to_first_time_enabled_as_quote[4]
exchange.locus.scl.meta.outr: den, dts[4], fs, l, mao, mdo, mdod, mnao, mnaq, mnd, mut, ndo, nou, nqu, otq[120], ots[306], qts[24], tem, tto[612], uoa, utd[154]
exchange.locus.scl.meta.outr.tem: ntt[28]
exchange.locus.scl.meta.spot_infos[]: deploy_time, tokens[2]
exchange.locus.scl.meta.token_infos[]: deploy_gas_token, deploy_gas_wei, deploy_time, deployer, deployer_trading_fee_share, evm_contract, frozen_users, full_name, non_circulating_users[0], seeded_usdc, spec, spots[1]
exchange.locus.scl.soh: sotq[1912], sots[14749], sqp[14749], sqpq[462], sqts[462]
exchange.locus.scl.token_to_genesis[][1]: blacklist_users[0], existing_token_balances[1], user_balances[3]
exchange.locus.scl.user_states[][1]: b[175]
exchange.locus.uac[][1]: m
exchange.locus.ust[][1]: C, P, s
exchange.locus.vlt[][1]: allow_deposits, always_close_on_withdraw, create_time, description, is_closed, leader, leader_commission, lockup_duration, name, relationship, s, user_states[49], vault_user
exchange.locus.vlt[][1].relationship: type
exchange.msc: aci, i, mou, mtpt, pmc, sgd, sog, sre[0], tce, tde, uta[2], vpv[22]
exchange.msc.mou: l, u[3]
exchange.msc.sog: bucket_millis, last_bucket
exchange.msc.vpv[][1]: time, version
exchange.multi_sig_tracker: user_to_multi_sig_signers[6117]
exchange.multi_sig_tracker.user_to_multi_sig_signers[][1]: authorizedUsers[4], threshold
exchange.oh[][1]: pxs2[234]
exchange.perp_deploy_gas_auction: bucket_guard, end_gas_wei, initial_gas_to_last_auction_gas_ratio, min_gas, start_gas_wei, token
exchange.perp_deploy_gas_auction.bucket_guard: bucket_millis, last_bucket
exchange.perp_dexs[]: books[234], funding_tracker, perp_to_annotation[123], twap_tracker
exchange.perp_dexs[].books[]: asset, bod, cloid_tracker, halfs[2], last_trade_px, oid_to_key[59570], total_sz, user_states[15985]
exchange.perp_dexs[].books[].bod: e[64684], l, n
exchange.perp_dexs[].books[].cloid_tracker: user_trackers[141549]
exchange.perp_dexs[].funding_tracker: asset_to_premiums[234], default_clamp, default_impact_usd, hl_only_perps[0], override_impact_usd[9], perp_to_funding_clamp[0], perp_to_funding_interest_rate[4], perp_to_funding_multiplier[129], use_binance_formula
exchange.perp_dexs[].perp_to_annotation[][1]: c, d, k[2], l, n
exchange.perp_dexs[].twap_tracker: running_heap[199], user_to_id_to_state[134], user_to_id_to_waiting[35]
exchange.perp_dexs[].twap_tracker.running_heap[]: next_slice_time, twap_id, user
exchange.pt: gpa[2], gpc, pgp[1134], prp
exchange.pt.gpa[]: a, cw, pw
exchange.pt.gpa[].a: bucket_guard, end_gas_wei, initial_gas_to_last_auction_gas_ratio, min_gas, start_gas_wei, token
exchange.pt.gpa[].a.bucket_guard: bucket_millis, last_bucket
exchange.pt.gpa[].pw: Ip[4]
exchange.pt.gpc: gm
exchange.pt.pgp[][1]: P, u, w
exchange.pt.prp: D, b, d, r
exchange.pvs: mptc, ptc
exchange.register_token_gas_auction: bucket_guard, end_gas_wei, initial_gas_to_last_auction_gas_ratio, min_gas, start_gas_wei, token
exchange.register_token_gas_auction.bucket_guard: bucket_millis, last_bucket
exchange.reserve_accumulators[][1]: ema, max_px, order_ntl, spot
exchange.reserve_accumulators[][1].ema: decay_duration, denom, last_sample_time, n_samples, num
exchange.spot_books[]: asset, bod, cloid_tracker, halfs[2], last_trade_px, oid_to_key[5205], total_sz, user_states[1075]
exchange.spot_books[].bod: e[6198], l, n
exchange.spot_books[].bod.e[]: o
exchange.spot_books[].cloid_tracker: user_trackers[1562]
exchange.spot_books[].halfs[]: levels[3471]
exchange.spot_books[].user_states[][1]: U[0], b[1], r[0], u[0]
exchange.spot_pair_deploy_gas_auction: bucket_guard, end_gas_wei, initial_gas_to_last_auction_gas_ratio, min_gas, start_gas_wei, token
exchange.spot_pair_deploy_gas_auction.bucket_guard: bucket_millis, last_bucket
exchange.spot_twap_tracker: running_heap[124], user_to_id_to_state[84], user_to_id_to_waiting[13]
exchange.spot_twap_tracker.running_heap[]: next_slice_time, twap_id, user
exchange.staking: active_epoch, allowed_validators[4], cur_epoch, cur_epoch_state, epoch_duration_seconds, epoch_states[8]
exchange.staking.cur_epoch_state: start_time, validator_states[4]
exchange.staking.cur_epoch_state.validator_states[][1]: cold_user, delegations[1], hot_user
exchange.staking.epoch_states[][1]: start_time, validator_states[4]
exchange.staking_link_tracker: user_to_staking_link2[2507]
exchange.staking_link_tracker.user_to_staking_link2[][1]: StakingUser, TradingUser
exchange.staking_link_tracker.user_to_staking_link2[][1].StakingUser: trading_user
exchange.staking_link_tracker.user_to_staking_link2[][1].TradingUser: staking_user
exchange.sub_account_tracker: sub_account_to_master[48293], user_to_sub_accounts[23803]
exchange.sub_account_tracker.user_to_sub_accounts[][1][]: m, n, s
exchange.user_to_evm_state[][1]: T, b, g, t
exchange.user_to_scheduled_cancel[][1]: t
exchange.validator_l1_stream_tracker: risk_free_rate
exchange.validator_l1_stream_tracker.risk_free_rate: b, m, v[13]
exchange.validator_l1_stream_tracker.risk_free_rate.b: bucket_millis, last_bucket
exchange.validator_l1_stream_tracker.risk_free_rate.v[][1]: t, v
exchange.validator_l1_vote_tracker: active, at2[0], hc, prune_bucket_guard
exchange.validator_l1_vote_tracker.hc: i, q
exchange.validator_l1_vote_tracker.prune_bucket_guard: bucket_millis, last_bucket
exchange.vtg: hsc[0], i[0], name
```

## Related pages

- [Generated order-book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots) — Use the purpose-built public snapshot format for reconstruction.
- [Raw book diffs](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/book-diffs) — Apply ordered changes after a known state seed.
- [L4 books](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book) — Consume the derived, order-level live view.

---

## Hyperliquid Blocks - replica_cmds Data

# Hyperliquid Blocks - replica_cmds Data

`replica_cmds` is the node-written block record. It contains signed action bundles, execution responses, and the consensus metadata needed for block-level replay and auditing.

Use this dataset when you need the full action record. Fills, order statuses, and book diffs are narrower feeds when you only need one kind of event.

## Access

| Availability  | Access                                                                                      | Details                                                                                                                                                                                                              |
| ------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live / replay | [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and [GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block) | V3 selects with `position.block_number` or `position.timestamp` and returns those cursors on `Record` alongside `data`. V2 selects with `block_height` or `timestamp_ms` and returns the JSON bytes in `Block.data`. |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                              | S3 coverage for `replica_cmds`: `2025-01-25` to today, stored as `LZ4-compressed native records`.                                                                                                                    |

## File layout

Blocks use this relative pattern:

```text
replica_cmds/<YYYYMMDD>/<chunk-start>.lz4
```

Each compressed file is JSONL and can contain multiple blocks, with one complete block object per line. Unlike the `*_by_block` datasets, `replica_cmds` does not use the shared events envelope.

The sequential block number is `chunk basename + zero-based line index + 1`. For example, the first line in `100.lz4` is block `101`, and the second line is block `102`.

## Sample data

```json
{
  "abci_block": {
    "time": "2026-01-01T00:00:00.000000000",
    "round": 42,
    "parent_round": 40,
    "proposer": "<redacted-proposer>",
    "hardfork": { "version": 1, "round": 10 },
    "signed_action_bundles": [
      [
        "<redacted-bundle-hash>",
        {
          "signed_actions": [
            {
              "signature": {
                "r": "<redacted-signature-r>",
                "s": "<redacted-signature-s>",
                "v": 27
              },
              "action": {
                "type": "order",
                "orders": [
                  {
                    "a": 170,
                    "b": true,
                    "p": "0.038385",
                    "s": "1514",
                    "r": false,
                    "t": { "limit": { "tif": "Ioc" } }
                  }
                ]
              },
              "nonce": 1704067200000
            }
          ],
          "broadcaster": "<redacted-broadcaster>"
        }
      ]
    ]
  },
  "resps": { "Full": [] }
}
```

This is synthetic representative data. Production addresses, hashes, and signatures use visible `<redacted-...>` markers.

## Important fields

| Field                              | Description                                                      |
| ---------------------------------- | ---------------------------------------------------------------- |
| `abci_block.time`                  | ISO-8601 consensus timestamp with sub-second precision.          |
| `abci_block.round`                 | HyperBFT consensus round. It is not the sequential block number. |
| `abci_block.parent_round`          | Parent consensus round. Consensus rounds may skip.               |
| `abci_block.proposer`              | Proposer address for the block.                                  |
| `abci_block.signed_action_bundles` | Signed user actions grouped into bundles.                        |
| `resps.Full`                       | Execution responses aligned with the action bundles.             |

Derive the sequential block number from the chunk basename and line index. Do not derive it from `abci_block.round`, because consensus rounds can skip.

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

Generated from 1,423 records in `replica_cmds/20261021/1191310000.lz4` (2026-10-21).

```text
abci_block                       object
  hardfork                       object
    round                        number
    version                      number
  parent_round                   number
  proposer                       string
  round                          number
  signed_action_bundles          array
  signed_action_bundles[]        array
  signed_action_bundles[][0]     string
  signed_action_bundles[][1]     object
    broadcaster                  string
    broadcaster_nonce            number
    signed_actions               array
    signed_actions[]             object
      action                     object
      action<NetChildVaultPositionsAction> object
        assets                   array
        assets[]                 number
        childVaultAddresses      array
        childVaultAddresses[]    string
      action<SetGlobalAction>    object
        externalPerpPxs          array
        externalPerpPxs[]        array
        externalPerpPxs[][]      string
        nativePx                 string
        pxs                      array
        pxs[]                    array
        pxs[][]                  null | string
        usdtUsdcPx               string
      action<ValidatorSignWithdrawalAction> object
        destination              string
        nonce                    number
        signature                object
          r                      string
          s                      string
          v                      number
        usd                      number
        user                     string
      action<VoteEthFinalizedWithdrawalAction> object
        destination              string
        ethTxHash                string
        nonce                    number
        usd                      number
        user                     string
      action<agentEnableDexAbstraction> object
      action<agentSendAsset>     object
        amount                   string
        destination              string
        destinationDex           string: xyz
        fromSubAccount           string
        nonce                    number
        sourceDex                string: ""
        token                    string
      action<agentSetAbstraction> object
        abstraction              string: u
      action<approveAgent>       object
        agentAddress             string
        agentName                null | string
        hyperliquidChain         string: Mainnet
        nonce                    number
        signatureChainId         string
      action<approveBuilderFee>  object
        builder                  string
        hyperliquidChain         string: Mainnet
        maxFeeRate               string
        nonce                    number
        signatureChainId         string
      action<batchModify>        object
        a                        bool
        modifies                 array
        modifies[]               object
          oid                    number | string
          order                  object
            a                    number
            b                    bool
            c                    string
            p                    string
            r                    bool
            s                    string
            t                    object
              limit              object
                tif              string: Alo, Gtc
              trigger            object
                isMarket         bool
                tpsl             string: sl, tp
                triggerPx        string
      action<borrowLend>         object
        amount                   null | string
        operation                string: repay, supply
        token                    number
      action<cDeposit>           object
        hyperliquidChain         string
        nonce                    number
        signatureChainId         string
        wei                      number
      action<cancel>             object
        cancels                  array
        cancels[]                object
          a                      number
          o                      number
        f                        bool
      action<cancelByCloid>      object
        cancels                  array
        cancels[]                object
          asset                  number
          cloid                  string
        f                        bool
      action<claimRewards>       object
      action<evmRawTx>           object
        data                     string
      action<modify>             object
        a                        bool
        oid                      number | string
        order                    object
          a                      number
          b                      bool
          c                      string
          p                      string
          r                      bool
          s                      string
          t                      object
            limit                object
              tif                string: Alo, Gtc
            trigger              object
              isMarket           bool
              tpsl               string: sl, tp
              triggerPx          string
      action<multiSig>           object
        payload                  object
          action                 object
          action<perpDeploy>     object
            setOracle            object
              dex                string: io, xyz
              externalPerpPxs    array
              externalPerpPxs[]  array
              externalPerpPxs[][] string
              markPxs            array
              markPxs[]          array
              markPxs[][]        array
              markPxs[][][]      string
              oraclePxs          array
              oraclePxs[]        array
              oraclePxs[][]      string
          multiSigUser           string
          outerSigner            string
        signatureChainId         string
        signatures               array
        signatures[]             object
          r                      string
          s                      string
          v                      number
      action<noop>               object
      action<order>              object
        builder                  object
          b                      string
          f                      number
        grouping                 object | string: na, normalTpsl, positionTpsl
          p                      number
        orders                   array
        orders[]                 object
          a                      number
          b                      bool
          c                      string
          p                      string
          r                      bool
          s                      string
          t                      object
            limit                object
              tif                string: Alo, FrontendMarket, Gtc, Ioc
            trigger              object
              isMarket           bool
              tpsl               string: sl, tp
              triggerPx          string
      action<perpDeploy>         object
        setFundingInterestRates  array
        setFundingInterestRates[] array
        setFundingInterestRates[][] string
        setOracle                object
          dex                    string: mkts, para
          externalPerpPxs        array
          externalPerpPxs[]      array
          externalPerpPxs[][]    string
          markPxs                array
          markPxs[]              array
          markPxs[][]            array
          markPxs[][][]          string
          oraclePxs              array
          oraclePxs[]            array
          oraclePxs[][]          string
      action<reserveRequestWeight> object
        weight                   number
      action<scheduleCancel>     object
        time                     number
      action<sendAsset>          object
        amount                   string
        destination              string
        destinationDex           string: "", spot, xyz
        fromSubAccount           string
        hyperliquidChain         string: Mainnet
        nonce                    number
        signatureChainId         string
        sourceDex                string: "", io, spot
        token                    string
      action<sendToEvmWithData>  object
        addressEncoding          string: base58, hex
        amount                   string
        data                     string
        destinationChainId       number
        destinationRecipient     string
        gasLimit                 number
        hyperliquidChain         string: Mainnet
        nonce                    number
        signatureChainId         string
        sourceDex                string: "", spot
        token                    string: USDC
      action<setReferrer>        object
        code                     string
      action<spotSend>           object
        amount                   string
        destination              string
        hyperliquidChain         string: Mainnet
        signatureChainId         string
        time                     number
        token                    string
      action<subAccountTransfer> object
        isDeposit                bool
        subAccountUser           string
        usd                      number
      action<trailingStop>       object
        activationPx             null
        asset                    number
        isBuy                    bool
        reduceOnly               bool
        retracement              object
          pct                    string
        sz                       string
      action<twapOrder>          object
        twap                     object
          a                      number
          b                      bool
          m                      number
          r                      bool
          s                      string
          t                      bool
      action<updateIsolatedMargin> object
        asset                    number
        isBuy                    bool
        ntli                     number
      action<updateLeverage>     object
        asset                    number
        isCross                  bool
        leverage                 number
      action<usdClassTransfer>   object
        amount                   string
        hyperliquidChain         string: Mainnet
        nonce                    number
        signatureChainId         string
        toPerp                   bool
      action<usdSend>            object
        amount                   string
        destination              string
        hyperliquidChain         string: Mainnet
        signatureChainId         string
        time                     number
      action<userDexAbstraction> object
        enabled                  bool
        hyperliquidChain         string
        nonce                    number
        signatureChainId         string
        user                     string
      action<userOutcome>        object
        mergeOutcome             object
          amount                 string
          outcome                number
      action<userSetAbstraction> object
        abstraction              string: u
        hyperliquidChain         string: Mainnet
        nonce                    number
        signatureChainId         string
        user                     string
      action<validatorL1UpdateReferenceOracle> object
        externalPerpPxs          array
        externalPerpPxs[]        array
        externalPerpPxs[][]      string
        oraclePxs                array
        oraclePxs[]              array
        oraclePxs[][]            string
        scalarUpdates            object
          nativePx               string
          usdtUsdcPx             string
      action<vaultTransfer>      object
        isDeposit                bool
        usd                      number
        vaultAddress             string
      action<voteAbciDigest>     object
        abciDigest               string
        height                   number
        signature                object
          r                      string
          s                      string
          v                      number
      action<voteAppHash>        object
        appHash                  string
        height                   number
        signature                object
          r                      string
          s                      string
          v                      number
      action<voteL1Hash>         object
        height                   number
        l1Hash                   string
        signature                object
          r                      string
          s                      string
          v                      number
      action<withdraw3>          object
        amount                   string
        destination              string
        hyperliquidChain         string: Mainnet
        signatureChainId         string
        time                     number
      expiresAfter               number
      isFrontend                 bool
      nonce                      number
      signature                  object
        r                        string
        s                        string
        v                        number
      vaultAddress               string
  time                           string
height                           number
resps                            object
  Full                           array
  Full[]                         array
  Full[][0]                      string
  Full[][1]                      array
  Full[][1][]                    object
    res                          object
      response                   object | string
      response<cancel>           object
        data                     object
          statuses               array
          statuses[]             object | string: success
            error                string
      response<default>          object
      response<order>            object
        data                     object
          statuses               array
          statuses[]             object | string: waitingForFill, waitingForTrigger
            error                string
            filled               object
              avgPx              string
              cloid              string
              oid                number
              totalSz            string
            resting              object
              cloid              string
              oid                number
      response<setGlobal>        object
        data                     array
      response<trailingStop>     object
        data                     object
          oid                    number
      response<twapOrder>        object
        data                     object
          status                 object
            error                string: Trading is halted.
            running              object
              twapId             number
      response<validatorVote>    object
        data                     bool
      status                     string: err, ok
    user                         null | string
```

## Related pages

- [gRPC API overview](https://www.dwellir.com/docs/hyperliquid/grpc) — Review raw-feed positioning, filtering, retention, and recovery.
- [Historical data](https://www.dwellir.com/docs/hyperliquid/historical-data) — Review archival coverage and object layouts for node-written datasets.
- [Miscellaneous events](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/misc-events) — Inspect ledger and system events emitted alongside block processing.

---

## Hyperliquid Raw Book Diffs - Node Data

# Hyperliquid Raw Book Diffs - Node Data

`node_raw_book_diffs_by_block` captures order-level additions, size changes, and removals. Diffs are incremental. You need an initial snapshot or another known state seed before you apply ordered diffs; raw diffs alone cannot establish the starting book.

## Access

| Availability  | Access                                                                                                                    | Details                                                                                                                                                                                                                                                                                                                                                           |
| ------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live / replay | [StreamRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs) and [GetRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/get_raw_book_diffs) | V3 selects with `position.block_number` or `position.timestamp`; `Record.block_number` and `Record.timestamp` are transport cursors. V3 supports the documented `users` and `coins` filters. V2 selects with `block_height` or `timestamp_ms` and returns source JSON bytes in `BlockRawBookDiffs.data`; it does not use the V3 record fields or filter contract. |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                            | S3 coverage for `node_raw_book_diffs_by_block`: `2026-01-22` to today, stored as `hourly .lz4`. Pair these objects with a snapshot or state seed.                                                                                                                                                                                                                 |

## File layout

```text
node_raw_book_diffs_by_block/<YYYYMMDD>/<hour>.lz4
```

Files contain JSON block envelopes with book mutations in `events`.

## Sample data

```json
{
  "local_time": "2026-01-01T00:00:00.100000000",
  "block_time": "2026-01-01T00:00:00.000000000",
  "block_number": 12345,
  "events": [
    {
      "user": "<redacted-user-a>",
      "oid": 101,
      "coin": "LTC",
      "side": "A",
      "px": "68.177",
      "raw_book_diff": { "new": { "sz": "5.33" } }
    },
    {
      "user": "<redacted-user-b>",
      "oid": 102,
      "coin": "xyz:XYZ100",
      "side": "A",
      "px": "25471.0",
      "raw_book_diff": "remove"
    },
    {
      "user": "<redacted-user-c>",
      "oid": 103,
      "coin": "IP",
      "side": "A",
      "px": "2.466",
      "raw_book_diff": { "update": { "origSz": "4.5", "newSz": "0.0" } }
    }
  ]
}
```

This is synthetic representative data. Production account and order identifiers are replaced or use visible `<redacted-...>` markers.

## Important fields

| Field                     | Description                                    |
| ------------------------- | ---------------------------------------------- |
| `user`                    | Owner of the resting order.                    |
| `coin`, `oid`             | Stable local-book key when used together.      |
| `side`, `px`              | Book side and price level.                     |
| `raw_book_diff.new.sz`    | Adds an order with the given size.             |
| `raw_book_diff.update`    | Changes resting size from `origSz` to `newSz`. |
| `raw_book_diff: "remove"` | Removes the order.                             |

Start from a snapshot or state seed that corresponds to a known point, then apply later envelopes in sequential `block_number` order. Detect gaps before advancing local state.

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

Generated from 2,993 records in `node_raw_book_diffs_by_block/20261021/14.lz4` (2026-10-21).

```text
block_number                     number
block_time                       string
events                           array
events[]                         object
  coin                           string
  oid                            number
  px                             string
  raw_book_diff                  object | string: remove
    new                          object
      insertBefore               number
      sz                         string
    update                       object
      newSz                      string
      origSz                     string
  side                           string: A, B
  user                           string
local_time                       string
```

## Related pages

- [Generated order-book snapshots](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots) — Start reconstruction from a known order-level state.
- [L4 books](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book) — Consume the maintained order-level view instead of rebuilding it yourself.
- [Order book WebSocket guide](https://www.dwellir.com/guides/order-book-server) — Build a resilient snapshot-and-update client.

---

## Hyperliquid Fills - node_fills_by_block Data

# Hyperliquid Fills - node_fills_by_block Data

`node_fills_by_block` records per-account execution details such as price, size, direction, realized PnL, fees, and optional builder attribution.

A single match can include one taker and multiple makers. Self-trades can place more than one fill for the same account in that match.

Within one block, group records by `(coin, tid)` to identify a match. Across blocks, include `block_number` or `block_time` in the match key.

When deduplicating individual fills, retain account and order identity, such as `oid`. This preserves separate fills from one account in a self-trade.

## Access

| Availability  | Access                                                                                    | Details                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live / replay | [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) and [GetFills](https://www.dwellir.com/docs/hyperliquid/get_fills) | V3 selects with `position.block_number` or `position.timestamp`; `Record.block_number` and `Record.timestamp` are transport cursors. V3 supports the documented `users` and `coins` filters, with fields combined using AND and values within a field using OR. V2 selects with `block_height` or `timestamp_ms` and returns source JSON bytes in `BlockFills.data`; it does not use the V3 record fields or filter contract. |
| Live / replay | [hl\_getBatchBlocks](https://www.dwellir.com/docs/hyperliquid/hl_getBatchBlocks)                                 | Returns `trades` fill blocks in an inclusive `[from, to]` range within retained data; older ranges are pruned and the newest block can briefly be unavailable.                                                                                                                                                                                                                                                                |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                            | S3 coverage for `node_trades`: `2025-03-22` to `2025-05-25`, stored as `.lz4`.                                                                                                                                                                                                                                                                                                                                                |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                            | S3 coverage for `node_fills`: `2025-05-25` to `2025-07-27`, stored as `.lz4`.                                                                                                                                                                                                                                                                                                                                                 |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                            | S3 coverage for `node_fills_by_block`: `2025-07-27` to today, stored as `hourly .lz4`.                                                                                                                                                                                                                                                                                                                                        |
| Historical    | [Tick data](https://www.dwellir.com/docs/hyperliquid/tick-data)                                                  | Provides a processed historical alternative.                                                                                                                                                                                                                                                                                                                                                                                  |
| Historical    | [Indexed fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                                | Provides indexed historical queries.                                                                                                                                                                                                                                                                                                                                                                                          |

## File layout

Current block-enveloped fills use this relative pattern:

```text
node_fills_by_block/<YYYYMMDD>/<hour>.lz4
```

Each file contains JSON block envelopes. Historical fill prefixes have other shapes, so choose a parser from the prefix and record structure.

## Sample data

```json
{
  "local_time": "2026-01-01T00:00:00.100000000",
  "block_time": "2026-01-01T00:00:00.000000000",
  "block_number": 12345,
  "events": [
    [
      "<redacted-user>",
      {
        "coin": "BTC",
        "px": "118136.0",
        "sz": "0.00009",
        "side": "B",
        "time": 1704067200000,
        "startPosition": "-1.41864",
        "dir": "Close Short",
        "closedPnl": "-0.003753",
        "hash": "<redacted-transaction-hash>",
        "oid": 101,
        "crossed": false,
        "fee": "-0.000212",
        "tid": 202,
        "cloid": "<redacted-client-order-id>",
        "feeToken": "USDC",
        "builder": "<redacted-builder>",
        "builderFee": "0.005528"
      }
    ]
  ]
}
```

This is synthetic representative data. Production account, transaction, order, trade, client-order, and builder identifiers are replaced or use visible `<redacted-...>` markers.

## Important fields

| Field                               | Description                                                                                           |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `events[i][0]`                      | Account whose execution record follows.                                                               |
| `block_number`, `coin`, `tid`       | Match identity across blocks. Within one block, `(coin, tid)` identifies the match.                   |
| `px`, `sz`, `side`                  | Execution price, size, and buy or ask side. Numeric values are strings.                               |
| `startPosition`, `dir`, `closedPnl` | Position and realized-PnL context for the account.                                                    |
| `oid`, `cloid`, `hash`              | Order, client-order, and transaction identifiers.                                                     |
| `crossed`                           | `true` for a taker fill and `false` for a maker fill.                                                 |
| `fee`, `feeToken`                   | Fee or rebate and its token.                                                                          |
| `builder`, `builderFee`             | Optional builder attribution.                                                                         |
| `twapId`                            | Optional parent TWAP identifier. Join to lifecycle `twap_id`; `oid` identifies the child order.       |
| `liquidation`                       | Optional metadata with `liquidatedUser`, `markPx`, and `method`. Counterparty fills can carry it too. |

Use [TWAP join and liquidation validation rules](https://www.dwellir.com/docs/hyperliquid/research) when analysing these fields. Preserve account and order identity when deduplicating fills.

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

### `node_trades`

Generated from 73,746 records in `node_trades/20250524/14.lz4` (2025-05-24).

```text
coin                             string
hash                             string
px                               string
side                             string: A, B
side_info                        array
side_info[]                      object
  cloid                          null | string
  oid                            number
  start_pos                      string
  twap_id                        null | number
  user                           string
sz                               string
time                             string
trade_dir_override               string: LiquidatedMarket, Na, NetChildVaultPositions
```

### `node_fills`

Generated from 261,810 records in `node_fills/20250726/14.lz4` (2025-07-26).

```text
[0]                              string
[1]                              object
  builder                        string
  builderFee                     string
  cloid                          string
  closedPnl                      string
  coin                           string
  crossed                        bool
  dir                            string: Buy, Close Long, Close Short, Long > Short, Net Child Vaults, Open Long, Open Short, Sell, Short > Long
  fee                            string
  feeToken                       string
  hash                           string
  liquidation                    object
    liquidatedUser               string
    markPx                       string
    method                       string: market
  oid                            number
  px                             string
  side                           string: A, B
  startPosition                  string
  sz                             string
  tid                            number
  time                           number
```

### `node_fills_by_block`

Generated from 49,867 records in `node_fills_by_block/20261021/14.lz4` (2026-10-21).

```text
block_number                     number
block_time                       string
events                           array
events[]                         array
events[][0]                      string
events[][1]                      object
  builder                        string
  builderFee                     string
  cloid                          string
  closedPnl                      string
  coin                           string
  crossed                        bool
  deployerFee                    string
  dir                            string
  fee                            string
  feeToken                       string
  hash                           string
  liquidation                    object
    liquidatedUser               string
    markPx                       string
    method                       string: market
  oid                            number
  priorityGas                    string
  px                             string
  side                           string: A, B
  startPosition                  string
  sz                             string
  tid                            number
  time                           number
  twapId                         null | number
local_time                       string
```

## Related pages

- [Matched trades](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/trades) — Use a match-level view when per-account fill records are unnecessary.
- [Derived fill views](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/fill-views) — Stream typed all-user, user, builder, and liquidation views.
- [Whale tracking guide](https://www.dwellir.com/guides/hyperliquid-whale-tracking) — Build a real-time workflow around large fills and resting orders.

---

## Hyperliquid Misc Events - Node Data

# Hyperliquid Misc Events - Node Data

`misc_events_by_block` carries miscellaneous L1 events, including ledger updates, transfers, staking activity, withdrawals, and system-generated records.

The event variants are open-ended. Branch on the discriminator inside `inner`, retain unknown variants, and treat documented variants as examples rather than a closed enum.

## Access

| Availability  | Access                                                                                                          | Details                                                                                                                                                                                                                                                                                                                                                                               |
| ------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live / replay | [StreamMiscEvents](https://www.dwellir.com/docs/hyperliquid/stream_misc_events) and [GetMiscEvents](https://www.dwellir.com/docs/hyperliquid/get_misc_events) | V3 selects with `position.block_number` or `position.timestamp`; `Record.block_number` and `Record.timestamp` are transport cursors. V3 supports the documented `users` filter. This feed does not accept `coins`. V2 selects with `block_height` or `timestamp_ms` and returns source JSON bytes in `BlockMiscEvents.data`; it does not use the V3 record fields or filter contract. |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                  | S3 coverage for `misc_events_by_block`: `2026-06-29` to today, stored as `hourly .lz4`.                                                                                                                                                                                                                                                                                               |

## File layout

```text
misc_events_by_block/<YYYYMMDD>/<hour>.lz4
```

Files contain JSON block envelopes. An envelope can have an empty `events` array. That records an empty source block; it is not a transport heartbeat and must not be used as proof that a connection is healthy.

## Sample data

```json
{
  "local_time": "2026-01-01T00:00:00.100000000",
  "block_time": "2026-01-01T00:00:00.000000000",
  "block_number": 12345,
  "events": [
    {
      "time": "2026-01-01T00:00:00.000000000",
      "hash": "<redacted-transaction-hash>",
      "inner": {
        "LedgerUpdate": {
          "users": [
            "<redacted-user-a>",
            "<redacted-user-b>"
          ],
          "delta": {
            "type": "spotTransfer",
            "token": "USDC",
            "amount": "100.058362"
          }
        }
      }
    }
  ]
}
```

This is synthetic representative data. Production transaction and account identifiers use visible `<redacted-...>` markers.

## Important fields

| Field                           | Description                                                                               |
| ------------------------------- | ----------------------------------------------------------------------------------------- |
| `time`                          | Event timestamp as an ISO-8601 string.                                                    |
| `hash`                          | Transaction hash. An all-zero value can identify a system-generated event.                |
| `inner`                         | Single-key variant object such as `LedgerUpdate`; handle an unknown discriminator safely. |
| `inner.LedgerUpdate.users`      | Accounts involved in the ledger update.                                                   |
| `inner.LedgerUpdate.delta.type` | Discriminator for the ledger action. Its remaining fields depend on the type.             |

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

Generated from 49,867 records in `misc_events_by_block/20261021/14.lz4` (2026-10-21).

```text
block_number                     number
block_time                       string
events                           array
events[]                         object
  hash                           string
  inner                          object
    CDeposit                     object
      amount                     string
      user                       string
    CWithdrawal                  object
      amount                     string
      is_finalized               bool
      user                       string
    CreateSubAccount             object
      name                       string
      sub_account                string
      user                       string
    Delegation                   object
      amount                     string
      is_undelegate              bool
      user                       string
      validator                  string
    Funding                      object
      deltas                     array
      deltas[]                   object
        coin                     string
        funding_amount           string
        funding_rate             string
        szi                      string
        user                     string
    GossipPriorityAuctionRestart object
      end_gas                    null | string
      previous_winner            null | object
        Ip                       string
      slot_id                    number
    LedgerUpdate                 object
      delta                      object
      delta<accountActivationGas> object
        amount                   string
        token                    string: HYPE, USDC
      delta<accountClassTransfer> object
        toPerp                   bool
        usdc                     string
      delta<borrowLend>          object
        amount                   string
        interestAmount           string
        operation                string: borrow, repay, supply, withdraw
        token                    string: HYPE, UBTC, USDC
      delta<cStakingTransfer>    object
        amount                   string
        isDeposit                bool
        token                    string: HYPE
      delta<deposit>             object
        usdc                     string
      delta<gossipPriorityGasAuction> object
        amount                   string
        token                    string: HYPE
      delta<internalTransfer>    object
        destination              string
        fee                      string
        usdc                     string
        user                     string
      delta<rewardsClaim>        object
        amount                   string
        token                    string: USDC
      delta<send>                object
        amount                   string
        destination              string
        destinationDex           string: "", io, para, spot, xyz
        fee                      string
        feeToken                 string: "", USDC, USDT0
        nativeTokenFee           string
        nonce                    number
        sourceDex                string: "", io, para, spot, xyz
        token                    string
        usdcValue                string
        user                     string
      delta<spotTransfer>        object
        amount                   string
        destination              string
        fee                      string
        feeToken                 string: "", HYPE, USDC
        nativeTokenFee           string
        nonce                    number
        token                    string
        usdcValue                string
        user                     string
      delta<subAccountTransfer>  object
        destination              string
        usdc                     string
        user                     string
      delta<vaultDeposit>        object
        usdc                     string
        vault                    string
      delta<vaultLeaderCommission> object
        usdc                     string
        user                     string
      delta<vaultWithdraw>       object
        basis                    string
        closingCost              string
        commission               string
        netWithdrawnUsd          string
        requestedUsd             string
        user                     string
        vault                    string
      delta<withdraw>            object
        fee                      string
        nonce                    number
        usdc                     string
      users                      array
      users[]                    string
    ValidatorRewards             object
      validator_to_reward        array
      validator_to_reward[]      array
      validator_to_reward[][]    string
  time                           string
local_time                       string
```

## Related pages

- [Blocks and actions](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks) — Pair event records with their surrounding block and execution responses.
- [HyperCore Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint) — Query current HyperCore state through request-response methods.
- [Clearinghouse state](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Read current perpetual positions and margin state for an account.

---

## Hyperliquid Order Statuses - Node Data

# Hyperliquid Order Statuses - Node Data

`node_order_statuses_by_block` records order lifecycle transitions. An event includes the order snapshot, account, status, transaction context, and optional builder attribution at that point in the lifecycle.

Use it to follow placement, filling, cancellation, and rejection behavior. Status strings are open-ended, so consumers must preserve and safely handle unknown status values.

## Access

| Availability  | Access                                                                                                                      | Details                                                                                                                                                                                                                                                                                                                                                            |
| ------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Live / replay | [StreamOrderStatuses](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses) and [GetOrderStatuses](https://www.dwellir.com/docs/hyperliquid/get_order_statuses) | V3 selects with `position.block_number` or `position.timestamp`; `Record.block_number` and `Record.timestamp` are transport cursors. V3 supports the documented `users` and `coins` filters. V2 selects with `block_height` or `timestamp_ms` and returns source JSON bytes in `BlockOrderStatuses.data`; it does not use the V3 record fields or filter contract. |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                              | S3 coverage for `node_order_statuses_by_block`: `2026-01-22` to today, stored as `hourly .lz4`.                                                                                                                                                                                                                                                                    |
| Historical    | [Indexed order history](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/historical-orders)                                        | Supports historical queries.                                                                                                                                                                                                                                                                                                                                       |

## File layout

```text
node_order_statuses_by_block/<YYYYMMDD>/<hour>.lz4
```

Files contain JSON block envelopes with status objects in `events`.

## Sample data

```json
{
  "local_time": "2026-01-01T00:00:00.100000000",
  "block_time": "2026-01-01T00:00:00.000000000",
  "block_number": 12345,
  "events": [
    {
      "time": "2026-01-01T00:00:00.000000000",
      "user": "<redacted-user>",
      "hash": "<redacted-transaction-hash>",
      "builder": { "b": "<redacted-builder>", "f": 50 },
      "status": "open",
      "order": {
        "coin": "LTC",
        "side": "A",
        "limitPx": "68.177",
        "sz": "5.33",
        "oid": 101,
        "timestamp": 1704067200000,
        "orderType": "Limit",
        "origSz": "5.33",
        "tif": "Alo",
        "reduceOnly": false,
        "cloid": "<redacted-client-order-id>"
      }
    }
  ]
}
```

This is synthetic representative data. Production account, transaction, builder, order, and client-order identifiers are replaced or use visible `<redacted-...>` markers. `builder` can be `null` or the compact object `{ b, f }`, where `b` is the builder address and `f` is its fee value.

## Important fields

| Field     | Description                                                                                                     |
| --------- | --------------------------------------------------------------------------------------------------------------- |
| `time`    | Status-event timestamp as an ISO-8601 string.                                                                   |
| `user`    | Account associated with the order.                                                                              |
| `hash`    | Transaction hash; some status variants use `null`.                                                              |
| `builder` | `null` or `{ b, f }` builder attribution.                                                                       |
| `status`  | Lifecycle value such as `open`, `filled`, or `canceled`, plus reason-coded variants. The set is not exhaustive. |
| `order`   | Order snapshot at the transition, including coin, side, price, size, IDs, and conditions.                       |

Key order identity by at least `(coin, oid)` because `oid` is not reliably unique across coins.

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

Generated from 671 records in `node_order_statuses_by_block/20261021/14.lz4` (2026-10-21).

```text
block_number                     number
block_time                       string
events                           array
events[]                         object
  builder                        null | object
    b                            string
    f                            number
  hash                           null | string
  order                          object
    children                     array
    children[]                   object
      children                   array
      cloid                      null | string
      coin                       string
      isPositionTpsl             bool
      isTrigger                  bool
      limitPx                    string
      oid                        number
      orderType                  string: Stop Limit, Stop Market, Take Profit Limit, Take Profit Market
      origSz                     string
      reduceOnly                 bool
      side                       string: A, B
      sz                         string
      tif                        null
      timestamp                  number
      triggerCondition           string
      triggerPx                  string
    cloid                        null | string
    coin                         string
    isPositionTpsl               bool
    isTrigger                    bool
    limitPx                      string
    oid                          number
    orderType                    string: Limit, Market, Stop Limit, Stop Market, Take Profit Limit, Take Profit Market, Trailing Stop Market, Vault Close
    origSz                       string
    reduceOnly                   bool
    side                         string: A, B
    sz                           string
    tif                          null | string: Alo, FrontendMarket, Gtc, Ioc
    timestamp                    number
    triggerCondition             string
    triggerPx                    string
  status                         string
  time                           string
  user                           string
local_time                       string
```

## Related pages

- [L4 books](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/l4-book) — Follow the current resting order set and typed order-level updates.
- [Open orders](https://www.dwellir.com/docs/hyperliquid/open-orders) — Query a user's current open orders.
- [Order action payload](https://www.dwellir.com/docs/hyperliquid/order) — Decode the signed action that creates an order.

---

## Hyperliquid TWAP Statuses - Node Data

# Hyperliquid TWAP Statuses - Node Data

`node_twap_statuses_by_block` records lifecycle updates for time-weighted average price (TWAP) orders. Each event includes the TWAP identifier, current aggregate state, and lifecycle status.

## Access

| Availability  | Access                                                                                                                  | Details                                                                                                                                                                                                                                                                                                                                                           |
| ------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Live / replay | [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses) and [GetTwapStatuses](https://www.dwellir.com/docs/hyperliquid/get_twap_statuses) | V3 selects with `position.block_number` or `position.timestamp`; `Record.block_number` and `Record.timestamp` are transport cursors. V3 supports the documented `users` and `coins` filters. V2 selects with `block_height` or `timestamp_ms` and returns source JSON bytes in `BlockTwapStatuses.data`; it does not use the V3 record fields or filter contract. |
| Archival      | [S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                          | S3 coverage for `node_twap_statuses_by_block`: `2026-07-01` to today, stored as `hourly .lz4`.                                                                                                                                                                                                                                                                    |

## File layout

```text
node_twap_statuses_by_block/<YYYYMMDD>/<hour>.lz4
```

Files contain JSON block envelopes with TWAP lifecycle objects in `events`.

For download planning, see [compressed size and file count](https://www.dwellir.com/docs/hyperliquid/historical-data#compressed-size-and-file-count). Measure TWAP statuses and fills separately for the same date range when you need both.

## Sample data

```json
{
  "local_time": "2026-01-01T00:00:00.100000000",
  "block_time": "2026-01-01T00:00:00.000000000",
  "block_number": 12345,
  "events": [
    {
      "time": "2026-01-01T00:00:00.000000000",
      "twap_id": 101,
      "state": {
        "coin": "kPEPE",
        "user": "<redacted-user>",
        "side": "B",
        "sz": "555555.0",
        "executedSz": "555555.0",
        "executedNtl": "1371.51378",
        "minutes": 5,
        "reduceOnly": false,
        "randomize": false,
        "timestamp": 1704067200000
      },
      "status": "finished"
    }
  ]
}
```

This is synthetic representative data. The production account identifier uses a visible `<redacted-user>` marker, and the TWAP identifier is synthetic.

## Important fields

| Field                                    | Description                                                                       |
| ---------------------------------------- | --------------------------------------------------------------------------------- |
| `twap_id`                                | TWAP order identifier.                                                            |
| `state.user`, `state.coin`, `state.side` | Account, market, and side.                                                        |
| `state.sz`                               | Target size as a numeric string.                                                  |
| `state.executedSz`, `state.executedNtl`  | Aggregate executed size and notional at this lifecycle boundary.                  |
| `state.minutes`                          | Requested duration in minutes.                                                    |
| `state.timestamp`                        | TWAP creation time in Unix milliseconds.                                          |
| `status`                                 | Lifecycle string or an object carrying an error. Treat the set as non-exhaustive. |

This is lifecycle state, not a fill-by-fill log. Use fills for individual executions.

Join `twap_id` to a fill's `twapId`, not its child-order `oid`. Aggregate execution fields describe lifecycle boundaries rather than continuous progress.

Use signed block actions and responses for submission attempts and cancellations. A fills-derived sample excludes TWAPs that never execute.

For activity already running at your selection's start, include earlier lifecycle records or a matching state seed. See [TWAP research validation](https://www.dwellir.com/docs/hyperliquid/research#how-do-i-join-twap-lifecycle-events-to-executions).

## Observed fields

`[]` marks an array element, `[0]` a tuple position, `<name>` an object whose `type` is that name, and `{key}` a map keyed by user, asset, or ID. Values after a colon are every distinct value seen for a short enum field. A field missing here can still appear in record types the sample did not contain.

Generated from 49,867 records in `node_twap_statuses_by_block/20261021/14.lz4` (2026-10-21).

```text
block_number                     number
block_time                       string
events                           array
events[]                         object
  state                          object
    coin                         string
    executedNtl                  string
    executedSz                   string
    minutes                      number
    randomize                    bool
    reduceOnly                   bool
    side                         string: A, B
    stopPx                       null | string
    sz                           string
    timestamp                    number
    trigger                      null | object
      above                      bool
      px                         string
    user                         string
  status                         object | string: activated, finished, stopped, terminated, waitingForTrigger
    error                        string
  time                           string
  twap_id                        number
local_time                       string
```

## Related pages

- [TWAP order action](https://www.dwellir.com/docs/hyperliquid/twapOrder) — Decode the signed payload that starts a TWAP.
- [TWAP cancel action](https://www.dwellir.com/docs/hyperliquid/twapCancel) — Decode TWAP cancellation payloads.
- [Indexed TWAP summaries](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-summaries) — Query execution-derived summaries for one user.
- [Indexed TWAP slice fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-slice-fills) — Query the individual executions produced by TWAP slices.

---

## debug_traceBlock - Hyperliquid RPC Method

# debug_traceBlock - Hyperliquid RPC Method

Traces all transactions in a block on Hyperliquid by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Hyperliquid - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Hyperliquid
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Hyperliquid:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Hyperliquid blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/hyperliquid/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/hyperliquid/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Hyperliquid RPC Method

# debug_traceBlockByHash - Hyperliquid RPC Method

Traces all transactions in a block on Hyperliquid identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Hyperliquid - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Hyperliquid
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Hyperliquid:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Hyperliquid:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/hyperliquid/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/hyperliquid/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Hyperliquid RPC Method

# debug_traceBlockByNumber - Hyperliquid RPC Method

Traces all transactions in a block on Hyperliquid identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Hyperliquid - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Hyperliquid execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Hyperliquid:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Hyperliquid:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/hyperliquid/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/hyperliquid/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Hyperliquid RPC Method

# debug_traceCall - Hyperliquid RPC Method

Traces a call on Hyperliquid without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Hyperliquid - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Hyperliquid
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
        "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
        "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    data: '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    data: '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    'data': '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
        "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Hyperliquid to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Hyperliquid:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Hyperliquid:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/hyperliquid/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/hyperliquid/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/hyperliquid/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Hyperliquid RPC Method

# debug_traceTransaction - Hyperliquid RPC Method

Traces a transaction execution on Hyperliquid by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Hyperliquid
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/hyperliquid/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByNumber) - Trace entire block

---

## delegations - HyperCore Info Endpoint

# delegations - HyperCore Info Endpoint

Get detailed staking delegation information for a user, including validator assignments, amounts, and delegation history.

The live response is an array of delegation records, not an object wrapper.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `delegations` endpoint is essential for:

- **Staking Management** — View detailed delegation information
- **Validator Tracking** — Monitor which validators you're delegating to
- **Rewards Analysis** — Track delegation performance and returns
- **Portfolio Optimization** — Analyze and rebalance delegation strategy

## Request Parameters

- `type` (`string, required`): parameter: Must be `"delegations"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "delegations",
  "user": "0x420a4ed7b6bb361da586868adec2f2bb9ab75e66"
}'
```

## Response Fields

- `validator` (`string, required`): Ethereum address of the validator
- `amount` (`string, required`): Amount of tokens delegated
- `lockedUntilTimestamp` (`integer, required`): Unix timestamp (milliseconds) when delegation unlocks

## Successful Response

```json
[
  {
    "validator": "0x420a4ed7b6bb361da586868adec2f2bb9ab75e66",
    "amount": "12505.32462249",
    "lockedUntilTimestamp": 1762449026533
  }
]
```

## Common Use Cases

### 1. View Delegation Portfolio

Display all active delegations:

```javascript
async function viewDelegationPortfolio(userAddress) {
  const delegations = await getDelegations(userAddress);

  console.log('=== Delegation Portfolio ===\n');
  console.log(`Total delegations: ${delegations.length}`);

  if (delegations.length === 0) {
    console.log('No active delegations');
  } else {
    console.log('Delegation details available');
  }
}

// Usage
await viewDelegationPortfolio('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
```

### 2. Monitor Delegation Status

Track delegation changes over time:

```javascript
async function monitorDelegationStatus(userAddress) {
  const delegations = await getDelegations(userAddress);

  return {
    delegationCount: delegations.length,
    hasActiveDelegations: delegations.length > 0,
    timestamp: new Date().toISOString()
  };
}

// Usage
const status = await monitorDelegationStatus('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
console.log('Delegation status:', status);
```

### 3. Build Staking Dashboard

Create a comprehensive staking dashboard:

```javascript
async function getStakingDashboard(userAddress) {
  try {
    const delegations = await getDelegations(userAddress);

    return {
      status: 'success',
      delegations: delegations,
      totalDelegations: delegations.length,
      isStaking: delegations.length > 0,
      lastUpdated: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message
    };
  }
}

// Usage
const dashboard = await getStakingDashboard('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
console.log('Staking Dashboard:', dashboard);
```

### 4. Check Delegation Diversity

Analyze delegation distribution:

```javascript
async function analyzeDelegationDiversity(userAddress) {
  const delegations = await getDelegations(userAddress);

  const analysis = {
    totalDelegations: delegations.length,
    isDiversified: delegations.length > 1,
    delegationStatus: delegations.length > 0 ? 'active' : 'none'
  };

  if (analysis.isDiversified) {
    console.log('Portfolio is diversified across multiple validators');
  } else if (analysis.totalDelegations === 1) {
    console.log('Portfolio concentrated in single validator');
  } else {
    console.log('No active delegations');
  }

  return analysis;
}
```

### 5. Track Delegation History

Monitor delegation changes:

```javascript
class DelegationTracker {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.history = [];
  }

  async recordSnapshot() {
    const delegations = await getDelegations(this.userAddress);

    const snapshot = {
      timestamp: Date.now(),
      delegationCount: delegations.length,
      delegations: delegations
    };

    this.history.push(snapshot);
    return snapshot;
  }

  getHistory() {
    return this.history;
  }

  detectChanges() {
    if (this.history.length < 2) return null;

    const latest = this.history[this.history.length - 1];
    const previous = this.history[this.history.length - 2];

    return {
      countChange: latest.delegationCount - previous.delegationCount,
      timestamp: latest.timestamp
    };
  }
}

// Usage
const tracker = new DelegationTracker('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
await tracker.recordSnapshot();
```

## Best Practices

1. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
2. **Cache strategically** — Cache delegation data for several minutes
3. **Handle empty states** — Account for users with no delegations
4. **Monitor regularly** — Track changes for portfolio management
5. **Compare snapshots** — Store historical data to detect changes

## Related Endpoints

- [**delegatorSummary**](https://www.dwellir.com/docs/hyperliquid/delegator-summary) — Get delegation summary
- [**validatorL1Votes**](https://www.dwellir.com/docs/hyperliquid/validator-l1-votes) — Get validator voting information
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user fee information

***

*Access real-time Hyperliquid delegation data with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## delegatorSummary - HyperCore Info Endpoint

# delegatorSummary - HyperCore Info Endpoint

Get comprehensive delegation summary for a delegator, including staking positions, rewards, and validator relationships.

The live response is a flat object with `delegated`, `undelegated`, `totalPendingWithdrawal`, and `nPendingWithdrawals`.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `delegatorSummary` endpoint is essential for:

- **Staking Portfolio** — View all delegations for a delegator
- **Rewards Tracking** — Monitor staking rewards across validators
- **Delegation Analysis** — Analyze delegation strategy and distribution
- **Validator Selection** — Evaluate current validator relationships

## Request Parameters

- `type` (`string, required`): parameter: Must be `"delegatorSummary"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "delegatorSummary",
  "user": "0x420a4ed7b6bb361da586868adec2f2bb9ab75e66"
}'
```

## Response Fields

- `delegated` (`string, required`): Total amount of tokens currently delegated
- `undelegated` (`string, required`): Total amount of tokens not delegated
- `totalPendingWithdrawal` (`string, required`): Total amount pending withdrawal
- `nPendingWithdrawals` (`integer, required`): Number of pending withdrawal requests

## Successful Response

```json
{
  "delegated": "12505.32462249",
  "undelegated": "10689.31366593",
  "totalPendingWithdrawal": "0.0",
  "nPendingWithdrawals": 0
}
```

## Common Use Cases

### 1. View Staking Portfolio

Display all delegations for a user:

```javascript
async function viewStakingPortfolio(userAddress) {
  const summary = await getDelegatorSummary(userAddress);

  console.log('=== Staking Portfolio ===\n');
  console.log(`Delegated: ${summary.delegated}`);
  console.log(`Undelegated: ${summary.undelegated}`);
  console.log(`Pending withdrawals: ${summary.nPendingWithdrawals}`);

  if (parseFloat(summary.delegated) === 0) {
    console.log('No active delegations');
  }
}

// Usage
await viewStakingPortfolio('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
```

### 2. Track Delegation Changes

Monitor changes in delegation status:

```javascript
async function trackDelegations(userAddress) {
  const summary = await getDelegatorSummary(userAddress);

  return {
    delegated: summary.delegated,
    undelegated: summary.undelegated,
    hasActiveDelegations: parseFloat(summary.delegated) > 0,
    timestamp: new Date().toISOString()
  };
}

// Usage
const status = await trackDelegations('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
console.log('Delegation status:', status);
```

### 3. Build Staking Dashboard

Create a comprehensive staking dashboard:

```javascript
async function getStakingDashboard(userAddress) {
  try {
    const summary = await getDelegatorSummary(userAddress);

    return {
      status: 'success',
      delegated: summary.delegated,
      undelegated: summary.undelegated,
      totalPendingWithdrawal: summary.totalPendingWithdrawal,
      nPendingWithdrawals: summary.nPendingWithdrawals,
      lastUpdated: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message
    };
  }
}
```

### 4. Compare Delegation Strategies

Analyze delegation distribution:

```javascript
async function analyzeDelegationStrategy(userAddress) {
  const summary = await getDelegatorSummary(userAddress);

  const analysis = {
    delegated: summary.delegated,
    undelegated: summary.undelegated,
    delegationStatus: parseFloat(summary.delegated) > 0 ? 'active' : 'inactive'
  };

  console.log('Delegation Analysis:', analysis);
  return analysis;
}
```

## Best Practices

1. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
2. **Cache data** — Cache delegation data for several minutes to reduce API calls
3. **Handle empty states** — Account for users with no delegations
4. **Monitor regularly** — Track delegation changes for portfolio management
5. **Implement pagination** — For users with many delegations, display in batches

## Related Endpoints

- [**delegations**](https://www.dwellir.com/docs/hyperliquid/delegations) — Get detailed staking delegation information
- [**validatorL1Votes**](https://www.dwellir.com/docs/hyperliquid/validator-l1-votes) — Get validator voting information
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account trading state
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user fee information

***

*Access real-time Hyperliquid delegation data with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## eth_accounts - Hyperliquid RPC Method

# eth_accounts - Hyperliquid RPC Method

Returns a list of addresses owned by the client on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for derivatives traders, DeFi protocols, and teams building high-frequency trading applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/hyperliquid/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Hyperliquid RPC Method

# eth_blockNumber - Hyperliquid RPC Method

Returns the number of the most recent block on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_blockNumber` is fundamental for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Syncing Applications** - Keep your dApp in sync with the latest Hyperliquid blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Hyperliquid block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Hyperliquid block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Hyperliquid block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))
print(f'Hyperliquid block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Hyperliquid block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Hyperliquid:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Hyperliquid:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Hyperliquid node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/hyperliquid/eth_syncing) - Check if node is still syncing

---

## eth_call - Hyperliquid RPC Method

# eth_call - Hyperliquid RPC Method

Executes a new message call immediately without creating a transaction on Hyperliquid. Used for reading smart contract state.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

The `eth_call` method serves these key scenarios for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Hyperliquid
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on perpetual futures trading, onchain order books, and institutional-grade derivatives

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';
const walletAddress = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Hyperliquid. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Hyperliquid
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Hyperliquid

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    data := common.FromHex("0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/hyperliquid/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/hyperliquid/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Hyperliquid RPC Method

# eth_chainId - Hyperliquid RPC Method

Returns the chain ID used for transaction signing on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_chainId` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on perpetual futures trading, onchain order books, and institutional-grade derivatives

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/hyperliquid/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/hyperliquid/eth_syncing) - Check sync status

---

## eth_estimateGas - Hyperliquid RPC Method

# eth_estimateGas - Hyperliquid RPC Method

Estimates the gas necessary to execute a transaction on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Hyperliquid
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x30e54c9bc205e19d693d53c0b0be92299d4191ea', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x30e54c9bc205e19d693d53c0b0be92299d4191ea', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Hyperliquid.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Hyperliquid may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x30e54c9bc205e19d693d53c0b0be92299d4191ea', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/hyperliquid/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/hyperliquid/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Hyperliquid RPC Method

# eth_feeHistory - Hyperliquid RPC Method

Returns historical gas fee data on Hyperliquid, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Hyperliquid without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Hyperliquid.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Hyperliquid) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/hyperliquid/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/hyperliquid/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/hyperliquid/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Hyperliquid RPC Method

# eth_gasPrice - Hyperliquid RPC Method

Returns the current gas price on Hyperliquid in wei.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Hyperliquid
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Hyperliquid. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Hyperliquid, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Hyperliquid: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Hyperliquid supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/hyperliquid/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/hyperliquid/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/hyperliquid/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Hyperliquid RPC Method

# eth_getBalance - Hyperliquid RPC Method

Returns the balance of a given address on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getBalance` is fundamental for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Hyperliquid
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Hyperliquid
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Hyperliquid. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Hyperliquid`);
  return balance;
}

displayBalance('0x30e54c9bc205e19d693d53c0b0be92299d4191ea');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Hyperliquid at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))
address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Hyperliquid')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Hyperliquid')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Hyperliquid.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/hyperliquid/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Hyperliquid RPC Method

# eth_getBlockByHash - Hyperliquid RPC Method

Returns information about a block by hash on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getBlockByHash` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Hyperliquid
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Hyperliquid.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Hyperliquid.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/hyperliquid/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Hyperliquid RPC Method

# eth_getBlockByNumber - Hyperliquid RPC Method

Returns information about a block by block number on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getBlockByNumber` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Hyperliquid
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x749f10b5acfaa7240d49fe6356f8b2a62991aeea630831d13fda8c99d28dd6af",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Hyperliquid with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Hyperliquid. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/hyperliquid/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionByHash) - Get transaction details

---

## eth_getCode - Hyperliquid RPC Method

# eth_getCode - Hyperliquid RPC Method

Returns the bytecode at a given address on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getCode` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Hyperliquid
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on perpetual futures trading, onchain order books, and institutional-grade derivatives

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Hyperliquid:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Hyperliquid:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/hyperliquid/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/hyperliquid/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Hyperliquid RPC Method

# eth_getFilterChanges - Hyperliquid RPC Method

Polls a filter on Hyperliquid for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getFilterChanges` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Hyperliquid
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Hyperliquid:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/hyperliquid/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Hyperliquid RPC Method

# eth_getFilterLogs - Hyperliquid RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Hyperliquid. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getFilterLogs` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Hyperliquid
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/hyperliquid/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Hyperliquid RPC Method

# eth_getLogs - Hyperliquid RPC Method

Returns an array of all logs matching a given filter object on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Hyperliquid for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Hyperliquid
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Hyperliquid.

```javascript
const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Hyperliquid enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Hyperliquid, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Hyperliquid RPC Method

# eth_getStorageAt - Hyperliquid RPC Method

Returns the value from a storage position at a given address on Hyperliquid. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getStorageAt` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **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 perpetual futures trading, onchain order books, and institutional-grade derivatives
- **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": [
    "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "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-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x30e54c9bc205e19d693d53c0b0be92299d4191ea', '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-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';

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-hyperliquid-mainnet-evm.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 = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
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-hyperliquid-mainnet-evm.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-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    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 Hyperliquid:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.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-hyperliquid-mainnet-evm.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 = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';
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 Hyperliquid:`);
  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/hyperliquid/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/hyperliquid/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/hyperliquid/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Hyperliquid RPC Method

# eth_getTransactionByHash - Hyperliquid RPC Method

Returns the information about a transaction by transaction hash on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getTransactionByHash` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Hyperliquid
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Hyperliquid. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Hyperliquid. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/hyperliquid/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Hyperliquid RPC Method

# eth_getTransactionCount - Hyperliquid RPC Method

Returns the number of transactions sent from an address on Hyperliquid, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getTransactionCount` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Hyperliquid
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x30e54c9bc205e19d693d53c0b0be92299d4191ea', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Hyperliquid nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x30e54c9bc205e19d693d53c0b0be92299d4191ea'
nonce = get_transaction_count(address)
print(f'Hyperliquid nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Hyperliquid nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Hyperliquid:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x30e54c9bc205e19d693d53c0b0be92299d4191ea');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/hyperliquid/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/hyperliquid/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Hyperliquid RPC Method

# eth_getTransactionReceipt - Hyperliquid RPC Method

Returns the receipt of a transaction by transaction hash on Hyperliquid. Receipt is only available for mined transactions.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_getTransactionReceipt` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Hyperliquid and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Hyperliquid. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Hyperliquid, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getLogs) - Query logs by filter

---

## eth_maxPriorityFeePerGas - Hyperliquid RPC Method

# eth_maxPriorityFeePerGas - Hyperliquid RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Hyperliquid. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Hyperliquid
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Hyperliquid priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Hyperliquid priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Hyperliquid priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Hyperliquid:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Hyperliquid:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/hyperliquid/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/hyperliquid/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/hyperliquid/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_newBlockFilter - Hyperliquid RPC Method

# eth_newBlockFilter - Hyperliquid RPC Method

Creates a filter on Hyperliquid that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_newBlockFilter` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Block Monitoring** - Detect new blocks on Hyperliquid as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Hyperliquid:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/hyperliquid/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/hyperliquid/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Hyperliquid RPC Method

# eth_newFilter - Hyperliquid RPC Method

Creates a filter object on Hyperliquid based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_newFilter` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Event Monitoring** - Subscribe to specific contract events on Hyperliquid such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to perpetual futures trading, onchain order books, and institutional-grade derivatives
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Hyperliquid:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/hyperliquid/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Hyperliquid RPC Method

# eth_newPendingTransactionFilter - Hyperliquid RPC Method

Creates a filter on Hyperliquid that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on Hyperliquid to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for perpetual futures trading, onchain order books, and institutional-grade derivatives

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Hyperliquid...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Hyperliquid:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/hyperliquid/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/hyperliquid/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_sendRawTransaction - Hyperliquid RPC Method

# eth_sendRawTransaction - Hyperliquid RPC Method

Submits a pre-signed transaction for broadcast to Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Hyperliquid
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x30e54c9bc205e19d693d53c0b0be92299d4191ea', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Hyperliquid mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/hyperliquid/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x30e54c9bc205e19d693d53c0b0be92299d4191ea")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/hyperliquid/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/hyperliquid/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/hyperliquid/eth_getTransactionReceipt) - Get transaction result

---

## eth_syncing - Hyperliquid RPC Method

# eth_syncing - Hyperliquid RPC Method

Returns the sync status of your Hyperliquid node - either `false` when fully synced, or an object describing the sync progress.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_syncing` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Hyperliquid node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Hyperliquid node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Hyperliquid node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/hyperliquid/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/hyperliquid/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/hyperliquid/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/hyperliquid/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Hyperliquid RPC Method

# eth_uninstallFilter - Hyperliquid RPC Method

Removes a filter on Hyperliquid that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`eth_uninstallFilter` is important for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/hyperliquid/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getFilterLogs) - Get all logs matching a filter

---

## evmRawTx payload - EVM Transactions

# evmRawTx payload - EVM Transactions

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `evmRawTx` payload records a raw HyperEVM transaction included in Hyperliquid block data.

## Sample Data

```json
{
  "signature": {
    "r": "0xd32b8218ae5299c1421560f39d56e25ffa12ffbfa8faa38768a01850787a4ad3",
    "s": "0x4a6ec5bb2ab212e0851a800f6e9eff5de75fb5802662ffe59ff98c789c4c4de4",
    "v": 28
  },
  "action": {
    "type": "evmRawTx",
    "data": "0x02f8b58203e78304083a8482aef4ce8482aef4ce83032523948549fd7ffc092f8366e416e129a622ec060104ea80b844a1d6012700001b00000000000000000bf8172fda000000000046cf76b73b80500001000000000000000000000000000000000000000026f9d2b528a25fd5f2a6568f47a1c001a02a409cb47713ca174e802b23a762d9d7fec900f63443d66aba5b26ef942d016aa04e426c68c1664757c974f059c91877d4703f0447fa8e5830071e406eac8882c6"
  },
  "nonce": 1768146670768
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xc54a7a279607a900c6c404332644d8000085920d310ac7d26913257a550b82eb)

## Field Reference

### Action Fields

| Field   | Type   | Description                     |
| ------- | ------ | ------------------------------- |
| `type`  | string | Always `"evmRawTx"`             |
| `rawTx` | string | RLP-encoded raw EVM transaction |

## HyperEVM Overview

HyperEVM is Hyperliquid's EVM-compatible execution layer that allows:

- Smart contract deployment and execution
- ERC-20 token operations
- DeFi protocol interactions
- Bridge operations between L1 and EVM

## Transaction Decoding

The `rawTx` field contains an RLP-encoded Ethereum transaction. Decoding it reveals:

- `to`: Destination contract or address
- `value`: ETH/native token amount
- `data`: Contract call data (function selector + parameters)
- `gasLimit`, `gasPrice`: Gas parameters

```python
from eth_account._utils.legacy_transactions import decode_transaction

def decode_evm_tx(raw_tx_hex):
    tx_bytes = bytes.fromhex(raw_tx_hex[2:])  # Remove 0x prefix
    decoded = decode_transaction(tx_bytes)
    return decoded
```

## Use Cases

### DeFi Activity Monitoring

Track smart contract interactions on HyperEVM:

```python
def process_evmRawTx_action(action):
    raw_tx = action.get('rawTx')
    # Decode and analyze the transaction
    print(f"EVM transaction: {raw_tx[:50]}...")
```

### Bridge Transaction Tracking

Monitor cross-layer bridge operations between Hyperliquid L1 and HyperEVM.

### Smart Contract Analytics

Analyze popular contract interactions and protocol usage patterns.

## Related Action Payloads

- [evmUserModify](https://www.dwellir.com/docs/hyperliquid/evmUserModify) - EVM user setting changes
- [withdraw3](https://www.dwellir.com/docs/hyperliquid/withdraw3) - External withdrawals

---

## evmUserModify payload - EVM User Settings

# evmUserModify payload - EVM User Settings

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `evmUserModify` payload records a change to a user's HyperEVM interaction settings.

## Sample Data

```json
{
  "signature": {
    "r": "0xa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
    "s": "0x6543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba987",
    "v": 28
  },
  "action": {
    "type": "evmUserModify",
    "enabled": true
  },
  "nonce": 1767949700000
}
```

## Field Reference

### Action Fields

| Field     | Type    | Description              |
| --------- | ------- | ------------------------ |
| `type`    | string  | Always `"evmUserModify"` |
| `enabled` | boolean | EVM access enabled       |

## Use Cases

### EVM Access Tracking

Monitor EVM setting changes:

```python
def process_evmUserModify_action(action):
    enabled = action.get('enabled')
    status = 'enabled' if enabled else 'disabled'
    print(f"EVM access {status}")
```

## Related Action Payloads

- [evmRawTx](https://www.dwellir.com/docs/hyperliquid/evmRawTx) - EVM transaction payloads

---

## exchangeStatus - HyperCore Info Endpoint

# exchangeStatus - HyperCore Info Endpoint

Get current Hyperliquid exchange status and timestamp for health monitoring and data freshness verification.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `exchangeStatus` endpoint is essential for:

- **Health Monitoring** — Verify exchange is operational
- **Data Freshness** — Check timestamp for data staleness
- **Maintenance Detection** — Monitor for special statuses
- **Uptime Tracking** — Build status dashboards

## Request Parameters

- `type` (`string, required`): parameter: Must be `"exchangeStatus"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "exchangeStatus"
}'
```

## Response Fields

- `time` (`integer, required`): Unix timestamp in milliseconds
- `specialStatuses` (`array, required`): Array of special status strings (empty during normal operation)

## Successful Response

```json
{
  "time": 1704067200000,
  "specialStatuses": []
}
```

## Common Use Cases

### 1. Check Data Freshness

```javascript
async function checkDataFreshness(maxAgeSeconds = 60) {
  const status = await getExchangeStatus();
  const now = Date.now();
  const age = (now - status.time) / 1000; // Convert to seconds

  if (age > maxAgeSeconds) {
    console.warn(`Warning: Exchange data is ${age.toFixed(1)}s old`);
    return false;
  }

  return true;
}

// Usage
const isFresh = await checkDataFreshness(30);
if (!isFresh) {
  console.log('Consider retrying or alerting');
}
```

### 2. Build Health Check Monitor

```javascript
class ExchangeHealthMonitor {
  constructor(checkIntervalMs = 30000) {
    this.checkIntervalMs = checkIntervalMs;
    this.isHealthy = true;
    this.lastCheck = null;
  }

  async start() {
    while (true) {
      try {
        const status = await getExchangeStatus();
        this.lastCheck = Date.now();

        const age = (Date.now() - status.time) / 1000;
        this.isHealthy = age < 60 && status.specialStatuses.length === 0;

        if (!this.isHealthy) {
          console.error('Exchange unhealthy:', {
            dataAge: age,
            specialStatuses: status.specialStatuses
          });
        }
      } catch (error) {
        console.error('Health check failed:', error);
        this.isHealthy = false;
      }

      await new Promise(r => setTimeout(r, this.checkIntervalMs));
    }
  }

  getStatus() {
    return {
      isHealthy: this.isHealthy,
      lastCheck: this.lastCheck
    };
  }
}

// Usage
const monitor = new ExchangeHealthMonitor();
monitor.start();
```

### 3. Status Dashboard Endpoint

```javascript
async function getDashboardStatus() {
  const status = await getExchangeStatus();
  const now = Date.now();
  const latency = now - status.time;

  return {
    status: status.specialStatuses.length === 0 ? 'operational' : 'maintenance',
    latency: `${latency}ms`,
    specialStatuses: status.specialStatuses,
    lastUpdate: new Date(status.time).toISOString()
  };
}
```

### 4. Alert on Special Statuses

```javascript
async function checkForAlerts() {
  const status = await getExchangeStatus();

  if (status.specialStatuses.length > 0) {
    // Send alert
    console.error('ALERT: Special statuses detected:', status.specialStatuses);
    await sendAlert({
      title: 'Hyperliquid Special Status',
      message: `Statuses: ${status.specialStatuses.join(', ')}`,
      timestamp: status.time
    });
  }
}
```

## Best Practices

1. **Poll regularly** (every 30-60 seconds) for monitoring dashboards
2. **Check freshness** before processing critical data
3. **Alert on special statuses** to catch maintenance periods
4. **Monitor latency** between your server time and exchange time
5. **Implement circuit breakers** when exchange is unhealthy

## Performance Tips

### Lightweight Health Check

```javascript
// Minimal health check for high-frequency monitoring
async function quickHealthCheck() {
  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 5000);

    const status = await fetch(ENDPOINT, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ type: 'exchangeStatus' }),
      signal: controller.signal
    });

    clearTimeout(timeout);
    return status.ok;
  } catch {
    return false;
  }
}
```

## Related Endpoints

- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata
- [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta) — Get spot trading metadata

***

*Monitor Hyperliquid exchange health with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## extraAgents - HyperCore Info Endpoint

# extraAgents - HyperCore Info Endpoint

Get information about extra agents configured for a user, including trading agents, permissions, and delegated access settings.

The live response is an array of agent records with `name`, `address`, and `validUntil`.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `extraAgents` endpoint is essential for:

- **Agent Management** — View all agents with access to the account
- **Permission Tracking** — Monitor agent permissions and access levels
- **Security Auditing** — Verify authorized agents and delegated access
- **Access Control** — Manage who can trade on behalf of the account

## Request Parameters

- `type` (`string, required`): parameter: Must be `"extraAgents"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "extraAgents",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `name` (`string, required`): Agent name/identifier
- `address` (`string, required`): Ethereum address of the agent
- `validUntil` (`integer, required`): Unix timestamp (milliseconds) when agent access expires

## Successful Response

```json
[
  {
    "name": "pampit",
    "address": "0xd0621288b7f42151d326442a950bb829703a343a",
    "validUntil": 1785838333108
  },
  {
    "name": "pampit2",
    "address": "0x846d88dafbccd9524d674c1a6ac5d470273ff041",
    "validUntil": 1778073895185
  }
]
```

## Common Use Cases

### 1. List All Agents

Display all agents with access to the account:

```javascript
async function listAgents(userAddress) {
  const agents = await getExtraAgents(userAddress);

  console.log('=== Account Agents ===\n');
  console.log(`Total agents: ${agents.length}`);

  if (agents.length === 0) {
    console.log('No extra agents configured');
  } else {
    console.log('Agents have access to this account');
  }
}

// Usage
await listAgents('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

### 2. Security Audit

Audit agent access for security:

```javascript
async function auditAgentAccess(userAddress) {
  const agents = await getExtraAgents(userAddress);

  const audit = {
    timestamp: new Date().toISOString(),
    agentCount: agents.length,
    hasAgents: agents.length > 0,
    securityStatus: agents.length === 0 ? 'no-agents' : 'agents-configured'
  };

  console.log('=== Security Audit ===\n');
  console.log(`Agent count: ${audit.agentCount}`);
  console.log(`Status: ${audit.securityStatus}`);

  return audit;
}

// Usage
const audit = await auditAgentAccess('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

### 3. Monitor Agent Changes

Track changes in agent configuration:

```javascript
class AgentMonitor {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.lastKnownCount = null;
  }

  async checkForChanges() {
    const agents = await getExtraAgents(this.userAddress);
    const currentCount = agents.length;

    if (this.lastKnownCount !== null) {
      const change = currentCount - this.lastKnownCount;

      if (change > 0) {
        console.log(`⚠️  ${change} new agent(s) added`);
      } else if (change < 0) {
        console.log(`✓ ${Math.abs(change)} agent(s) removed`);
      }
    }

    this.lastKnownCount = currentCount;

    return {
      currentCount: currentCount,
      changed: this.lastKnownCount !== null && currentCount !== this.lastKnownCount
    };
  }
}

// Usage
const monitor = new AgentMonitor('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
setInterval(() => monitor.checkForChanges(), 60000); // Check every minute
```

### 4. Build Agent Dashboard

Create agent management dashboard:

```javascript
async function getAgentDashboard(userAddress) {
  try {
    const agents = await getExtraAgents(userAddress);

    return {
      status: 'success',
      agents: agents,
      totalAgents: agents.length,
      hasAgents: agents.length > 0,
      lastUpdated: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message,
      agents: []
    };
  }
}

// Usage
const dashboard = await getAgentDashboard('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log('Agent Dashboard:', dashboard);
```

### 5. Verify Agent Authorization

Check if agents are properly authorized:

```javascript
async function verifyAgentAuthorization(userAddress) {
  const agents = await getExtraAgents(userAddress);

  const verification = {
    isConfigured: agents.length > 0,
    agentCount: agents.length,
    status: agents.length > 0 ? 'agents-active' : 'no-agents',
    recommendation: agents.length > 0
      ? 'Review agent permissions regularly'
      : 'No agents configured'
  };

  console.log('Agent Authorization:', verification);
  return verification;
}

// Usage
const verification = await verifyAgentAuthorization('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

## Best Practices

1. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
2. **Cache data** — Cache agent data for several minutes
3. **Monitor changes** — Track agent additions/removals for security
4. **Regular audits** — Periodically review agent access for security
5. **Handle empty states** — Account for users without extra agents

## Security Considerations

### Regular Security Checks

```javascript
class SecurityChecker {
  constructor(userAddress, checkIntervalMs = 300000) {
    this.userAddress = userAddress;
    this.checkIntervalMs = checkIntervalMs; // 5 minutes
  }

  async performSecurityCheck() {
    const data = await getExtraAgents(this.userAddress);

    const securityReport = {
      timestamp: new Date().toISOString(),
      agentCount: data.agents.length,
      status: data.agents.length === 0 ? 'secure-no-agents' : 'review-required'
    };

    if (data.agents.length > 0) {
      console.log(`⚠️  Security Review: ${data.agents.length} agent(s) have access`);
    } else {
      console.log('✓ Security Check: No extra agents');
    }

    return securityReport;
  }

  async startMonitoring() {
    // Initial check
    await this.performSecurityCheck();

    // Periodic checks
    setInterval(() => this.performSecurityCheck(), this.checkIntervalMs);
  }
}
```

## Related Endpoints

- [**subAccounts**](https://www.dwellir.com/docs/hyperliquid/sub-accounts) — Get sub-account information
- [**userRole**](https://www.dwellir.com/docs/hyperliquid/user-role) — Get user role information
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get orders placed by agents

***

*Manage agent access and permissions with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## frontendOpenOrders - HyperCore Info Endpoint

# frontendOpenOrders - HyperCore Info Endpoint

Get open orders formatted specifically for frontend display, with optimized data structure for UI rendering.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `frontendOpenOrders` endpoint is essential for:

- **UI Development** — Build trading interfaces with pre-formatted order data
- **Order Display** — Show orders in user-friendly format
- **Real-time Updates** — Refresh order books in trading applications
- **Frontend Optimization** — Use data already structured for display

## Request Parameters

- `type` (`string, required`): parameter: Must be `"frontendOpenOrders"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "frontendOpenOrders",
  "user": "0x31ca8395cf837de08b24da3f660e77761dfb974b"
}'
```

## Response Fields

- `orders` (`array, required`): Array of order objects optimized for frontend display

## Successful Response

```json
{
  "orders": []
}
```

## Common Use Cases

### 1. Display Open Orders in UI

Render orders in a trading interface:

```javascript
async function displayOpenOrders(userAddress) {
  const data = await getFrontendOpenOrders(userAddress);

  console.log('=== Open Orders ===\n');

  if (data.orders.length === 0) {
    console.log('No open orders');
  } else {
    console.log(`${data.orders.length} open order(s)`);
    // Render orders in UI
  }
}

// Usage
await displayOpenOrders('0x31ca8395cf837de08b24da3f660e77761dfb974b');
```

### 2. Real-time Order Updates

Poll for order updates:

```javascript
class OrderUpdateManager {
  constructor(userAddress, updateIntervalMs = 5000) {
    this.userAddress = userAddress;
    this.updateIntervalMs = updateIntervalMs;
    this.onUpdate = null;
  }

  async start(callback) {
    this.onUpdate = callback;

    while (true) {
      try {
        const orders = await getFrontendOpenOrders(this.userAddress);
        if (this.onUpdate) {
          this.onUpdate(orders);
        }
      } catch (error) {
        console.error('Failed to fetch orders:', error);
      }

      await new Promise(r => setTimeout(r, this.updateIntervalMs));
    }
  }
}

// Usage
const manager = new OrderUpdateManager('0x31ca8395cf837de08b24da3f660e77761dfb974b');
manager.start((orders) => {
  console.log(`Updated: ${orders.orders.length} orders`);
  // Update UI
});
```

### 3. Build Order Management Panel

Create order management interface:

```javascript
async function getOrderPanel(userAddress) {
  try {
    const data = await getFrontendOpenOrders(userAddress);

    return {
      status: 'success',
      orders: data.orders,
      totalOrders: data.orders.length,
      hasOrders: data.orders.length > 0,
      lastUpdated: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message,
      orders: []
    };
  }
}

// Usage
const panel = await getOrderPanel('0x31ca8395cf837de08b24da3f660e77761dfb974b');
console.log('Order Panel:', panel);
```

### 4. Monitor Order Count

Track changes in order count:

```javascript
async function monitorOrderCount(userAddress) {
  let previousCount = null;

  const check = async () => {
    const data = await getFrontendOpenOrders(userAddress);
    const currentCount = data.orders.length;

    if (previousCount !== null && currentCount !== previousCount) {
      const change = currentCount - previousCount;
      console.log(`Order count changed: ${change > 0 ? '+' : ''}${change}`);
    }

    previousCount = currentCount;
    return currentCount;
  };

  return check;
}

// Usage
const checkOrders = await monitorOrderCount('0x31ca8395cf837de08b24da3f660e77761dfb974b');
setInterval(checkOrders, 10000); // Check every 10 seconds
```

### 5. Order Status Dashboard

Create comprehensive order status view:

```javascript
async function getOrderStatusDashboard(userAddress) {
  const data = await getFrontendOpenOrders(userAddress);

  return {
    totalOrders: data.orders.length,
    status: data.orders.length > 0 ? 'active' : 'no-orders',
    timestamp: new Date().toISOString(),
    orders: data.orders
  };
}

// Usage
const dashboard = await getOrderStatusDashboard('0x31ca8395cf837de08b24da3f660e77761dfb974b');
console.log('Order Dashboard:', dashboard);
```

## Best Practices

1. **Poll efficiently** — Update every 3-10 seconds for active trading UIs
2. **Handle empty states** — Display appropriate message when no orders exist
3. **Optimize rendering** — Only re-render when order data changes
4. **Validate addresses** — Ensure user addresses are valid before requests
5. **Implement caching** — Cache briefly (1-5 seconds) to reduce redundant calls

## Performance Tips

### Efficient Polling Strategy

```javascript
class SmartOrderPoller {
  constructor(userAddress, baseInterval = 5000) {
    this.userAddress = userAddress;
    this.baseInterval = baseInterval;
    this.lastData = null;
  }

  async poll() {
    const data = await getFrontendOpenOrders(this.userAddress);

    // Only notify if data changed
    const hasChanged = JSON.stringify(data) !== JSON.stringify(this.lastData);
    this.lastData = data;

    return {
      data: data,
      changed: hasChanged
    };
  }
}
```

## Related Endpoints

- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get standard open orders format
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get fee information for orders
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata

***

*Build powerful trading interfaces with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## GetBlock - Get Block Data

# GetBlock - Get Block Data

Retrieve a single block at a specific position from the Hyperliquid L1 Gateway.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetBlock` is essential for:

- **Point-in-Time Analysis** - Get blockchain state at a specific block or timestamp
- **Backtesting** - Retrieve historical block data for strategy analysis
- **Auditing** - Verify transactions and state changes at specific points
- **Debugging** - Investigate specific blocks during development

Method signature

```protobuf
rpc GetBlock(GetRequest) returns (Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`; explicit zero is invalid. A positioned call returns the selected block record. An empty `GetRequest` waits for the next block written after the call begins, so set a deadline. Blocks do not accept filters.

```protobuf
position: {
  block_number: 1058646974
}
```

The V3 `Record` contains optional sequential `block_number` and Unix-millisecond `timestamp` cursors plus raw `replica_cmds` bytes in `data`. The sequential cursor is distinct from `abci_block.round`. A pruned position returns `NOT_FOUND`; an above-head block returns `OUT_OF_RANGE`; malformed cursors and filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to wait for the next written record.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetBlock
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the replica_cmds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"abci_block\":{\"round\":1058646981,\"signed_action_bundles\":[]},\"resps\":{\"Full\":[]}}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter was supplied to a feed that does not support filtering.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Position ahead of head

- Code: `OUT_OF_RANGE`
- Description: The requested block is above the feed's current head and may become available later.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to target the latest data.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to target the latest data.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetBlock
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 Block wrapper.

### Successful Response

```protobuf
message Block {
  bytes data = 1;
}
```

```protobuf
rpc GetBlock(Position) returns (Block) {}
```

V2 accepts `block_height` or Unix-millisecond `timestamp_ms` and returns the source JSON in `Block.data`.

## Common Use Cases

For V3, select the block with `GetRequest.position.block_number`, then decode the returned `Record.data`. Use the decoded `replica_cmds` payload to analyze signed actions, compare blocks, or locate a transaction hash. See [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks#full-block-spec) for the complete decoded shape.

### 1. Historical Block Analysis

```python
def analyze_block_activity(client, block_height):
    """Analyze trading activity in a specific block"""
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetBlock(request, metadata=metadata)
    block = json.loads(response.data)

    abci_block = block.get('abci_block', {})
    bundles = abci_block.get('signed_action_bundles', [])

    analysis = {
        'consensus_round': abci_block.get('round'),
        'timestamp': abci_block.get('time'),
        'total_bundles': len(bundles),
        'total_actions': 0,
        'order_count': 0,
        'cancel_count': 0,
        'transfer_count': 0
    }

    for bundle in bundles:
        if len(bundle) >= 2:
            for action in bundle[1].get('signed_actions', []):
                analysis['total_actions'] += 1
                action_type = action.get('action', {}).get('type', '')

                if action_type == 'order':
                    analysis['order_count'] += 1
                elif action_type in ['cancel', 'cancelByCloid']:
                    analysis['cancel_count'] += 1
                elif action_type in ['spotSend', 'usdSend', 'withdraw3']:
                    analysis['transfer_count'] += 1

    return analysis
```

### 2. Block Comparison

```go
func compareBlocks(client pb.HyperliquidL1GatewayClient, ctx context.Context, height1, height2 int64) {
    block1, _ := client.GetBlock(ctx, &pb.Position{Position: &pb.Position_BlockHeight{BlockHeight: height1}})
    block2, _ := client.GetBlock(ctx, &pb.Position{Position: &pb.Position_BlockHeight{BlockHeight: height2}})

    var data1, data2 map[string]interface{}
    json.Unmarshal(block1.Data, &data1)
    json.Unmarshal(block2.Data, &data2)

    abci1 := data1["abci_block"].(map[string]interface{})
    abci2 := data2["abci_block"].(map[string]interface{})

    bundles1 := abci1["signed_action_bundles"].([]interface{})
    bundles2 := abci2["signed_action_bundles"].([]interface{})

    fmt.Printf("Block %d: %d bundles\n", height1, len(bundles1))
    fmt.Printf("Block %d: %d bundles\n", height2, len(bundles2))
}
```

### 3. Transaction Verification

```javascript
async function verifyTransaction(client, metadata, txHash, blockHeight) {
    return new Promise((resolve, reject) => {
        const request = { block_height: blockHeight };

        client.GetBlock(request, metadata, (error, response) => {
            if (error) {
                reject(error);
                return;
            }

            const block = JSON.parse(response.data);
            const bundles = block.abci_block?.signed_action_bundles || [];

            for (const bundle of bundles) {
                const bundleHash = bundle[0];
                if (bundleHash === txHash) {
                    resolve({
                        found: true,
                        consensus_round: block.abci_block.round,
                        bundle_data: bundle[1]
                    });
                    return;
                }
            }

            resolve({ found: false });
        });
    });
}
```

## Best Practices

1. **Position Selection**: Use the exact sequential block cursor for precise queries; timestamp lookups may return different blocks across requests near block boundaries
2. **Data Validation**: Always validate JSON structure before processing
3. **Error Recovery**: Implement retry logic with exponential backoff
4. **Resource Management**: Close gRPC connections properly to avoid resource leaks
5. **Caching**: Cache block data when analyzing the same blocks multiple times

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[StreamBlocks Documentation](https://www.dwellir.com/docs/hyperliquid/stream_blocks)** - Full block specification and action types reference

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetFills - Get Fill Data

# GetFills - Get Fill Data

Retrieve fills at a specific position from the Hyperliquid L1 Gateway.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetFills` is essential for:

- **Trade Reconciliation** - Verify fills at a specific point in time
- **Historical Analysis** - Retrieve fill data for backtesting or reporting
- **Auditing** - Verify trade executions at specific blocks
- **Liquidation Detection** - Identify forced position closures at specific blocks
- **Debugging** - Investigate specific fills during development

Method signature

```protobuf
rpc GetFills(GetRequest) returns (Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`; explicit zero is invalid. A positioned call returns the selected envelope. An empty `GetRequest` waits for the next fills record written after the call begins, so set a deadline.

```protobuf
position: {
  block_number: 1058646974
}
filter: {
  fields: {
    field: "coins"
    op: FILTER_OP_IN
    values: "BTC"
  }
}
```

Fills accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. A zero-match unary request returns the selected `Record` with `data` containing `events: []`. The record also exposes optional `block_number` and `timestamp` cursors. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to wait for the next written record.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetFills
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_fills_by_block, with non-matching events removed when a filter is applied.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Position ahead of head

- Code: `OUT_OF_RANGE`
- Description: The requested block is above the feed's current head and may become available later.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to target the latest data.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to target the latest data.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetFills
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockFills wrapper.

### Successful Response

```protobuf
message BlockFills {
  bytes data = 1;
}
```

```protobuf
rpc GetFills(Position) returns (BlockFills) {}
```

V2 accepts `block_height` or Unix-millisecond `timestamp_ms` and returns the source JSON in `BlockFills.data`.

## Common Use Cases

For V3, select each block with `GetRequest.position.block_number`, decode `Record.data`, and process its `events` array. The decoded payload supports the same PnL, volume, fill-verification, and liquidation workflows described in the [StreamFills field reference](https://www.dwellir.com/docs/hyperliquid/stream_fills#full-fill-spec).

### 1. PnL Reconciliation

```python
def reconcile_pnl(client, metadata, start_block, end_block):
    """Calculate total PnL between two blocks"""
    pnl_by_address = {}

    for block_height in range(start_block, end_block + 1):
        request = hyperliquid_pb2.Position(block_height=block_height)
        response = client.GetFills(request, metadata=metadata)
        fills = json.loads(response.data)

        for event in fills.get('events', []):
            if len(event) >= 2:
                address = event[0]
                fill = event[1]
                pnl = float(fill.get('closedPnl', 0))

                if address not in pnl_by_address:
                    pnl_by_address[address] = 0
                pnl_by_address[address] += pnl

    return pnl_by_address
```

### 2. Fill Verification

```go
func verifyFill(client pb.HyperliquidL1GatewayClient, ctx context.Context, blockHeight int64, traderId string) []map[string]interface{} {
    request := &pb.Position{Position: &pb.Position_BlockHeight{BlockHeight: blockHeight}}
    response, _ := client.GetFills(ctx, request)

    var fills map[string]interface{}
    json.Unmarshal(response.Data, &fills)

    var traderFills []map[string]interface{}
    events := fills["events"].([]interface{})

    for _, event := range events {
        eventArr := event.([]interface{})
        if len(eventArr) >= 2 {
            address := eventArr[0].(string)
            if address == traderId {
                fillData := eventArr[1].(map[string]interface{})
                traderFills = append(traderFills, fillData)
            }
        }
    }

    return traderFills
}
```

### 3. Volume Analysis

```javascript
function analyzeVolume(fills) {
    const volumeByCoin = {};
    const events = fills.events || [];

    for (const event of events) {
        if (event.length >= 2) {
            const fill = event[1];
            const coin = fill.coin;
            const volume = parseFloat(fill.sz) * parseFloat(fill.px);

            if (!volumeByCoin[coin]) {
                volumeByCoin[coin] = {
                    totalVolume: 0,
                    buyVolume: 0,
                    sellVolume: 0,
                    fillCount: 0
                };
            }

            volumeByCoin[coin].totalVolume += volume;
            volumeByCoin[coin].fillCount++;

            if (fill.side === 'B') {
                volumeByCoin[coin].buyVolume += volume;
            } else {
                volumeByCoin[coin].sellVolume += volume;
            }
        }
    }

    return volumeByCoin;
}
```

### 4. Liquidation Detection

```python
def find_liquidations(client, metadata, block_height):
    """Find liquidation events at a specific block"""
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetFills(request, metadata=metadata)
    fills = json.loads(response.data)

    liquidations = []
    for event in fills.get('events', []):
        if len(event) >= 2:
            address = event[0]
            fill = event[1]

            liq = fill.get('liquidation')
            if liq and liq['liquidatedUser'] == address and 'Close' in fill.get('dir', ''):
                liquidations.append({
                    'user': address,
                    'coin': fill['coin'],
                    'size': fill['sz'],
                    'price': fill['px'],
                    'mark_price': liq['markPx'],
                    'method': liq['method'],
                    'pnl': fill['closedPnl']
                })

    return liquidations
```

`GetFills` returns the same fill format as `StreamFills`. See the [StreamFills documentation](https://www.dwellir.com/docs/hyperliquid/stream_fills) for the complete field reference, including [liquidation data](https://www.dwellir.com/docs/hyperliquid/stream_fills#liquidation-data) and [maker vs taker](https://www.dwellir.com/docs/hyperliquid/stream_fills#maker-vs-taker) details.

## Best Practices

1. **Position Selection**: Use the exact sequential block cursor for precise queries; timestamp lookups may return different fills across requests
2. **Data Validation**: Always validate JSON structure and handle optional fields
3. Within one block, group a match by `(coin, tid)`. Across blocks, include `block_number` or `block_time`. Retain account and order identity when deduplicating individual fills.
4. **Error Recovery**: Implement retry logic with exponential backoff
5. **Resource Management**: Close gRPC connections properly to avoid resource leaks

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[StreamFills Documentation](https://www.dwellir.com/docs/hyperliquid/stream_fills)** - Full fill specification and streaming examples
- **[Copy Trading Bot](https://github.com/dwellir-public/gRPC-code-examples/tree/main/copy-trading-bot)** - Production-ready example using fill data

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetMempoolTxs - Get a Pre-Consensus Client Block

# GetMempoolTxs - Get a Pre-Consensus Client Block

Retrieve one pre-consensus client block by receive time. This method is V3-only and returns the same `Record` shape as [StreamMempoolTxs](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs).

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable V3 client setup in Go, Python, and Node.js.

A request in a mempool record is not guaranteed to land in a block. It can still fail, be replaced, be reordered, or never be included.

We guarantee mempool data availability only in our Tokyo region.

## When to Use This Method

`GetMempoolTxs` is useful for:

- **Point lookups** - Fetch the client block received at or after a given time
- **Stepping through records** - Walk records one at a time with `timestamp_ns`
- **Spot checks** - Inspect pre-consensus traffic without holding a stream open

## Method signature

```protobuf
rpc GetMempoolTxs(GetRequest) returns (Record) {}
```

Set `position.timestamp` (Unix milliseconds) or `position.timestamp_ns` (Unix nanoseconds); both are inclusive and select the first record at or after that time. `position.block_number`, any `filter` constraint, and an explicit zero cursor return `INVALID_ARGUMENT`.

An empty `GetRequest` waits for the next client block the node receives, which can take minutes while upstream peers are quiet. Always set a deadline on an unpositioned call.

A record can exceed the default 4 MiB gRPC receive limit. Raise the client inbound message limit well above the default before calling.

## Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive Unix-millisecond receive-time cursor. Several records can share one millisecond. Omit the position to wait for the next client block the node receives.
- `position.timestamp_ns` (`int64, optional`): Inclusive Unix-nanosecond receive-time cursor; the exact resume cursor for this feed. Explicit zero is invalid.

## Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -max-msg-sz 67108864 \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"timestamp_ns":"1790611197799360275"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetMempoolTxs
```

## Response Fields

- `block_number` (`optional int64, optional`): Always unset. Mempool records are pre-consensus and belong to no block.
- `timestamp` (`optional int64, optional`): Time the node received the client block, in Unix milliseconds.
- `data` (`bytes, required`): The source line as bytes: a JSON array of the receive time and the client block, with its tx_hash and signed_actions.
- `timestamp_ns` (`optional int64, optional`): The receive time in Unix nanoseconds. Resume from it with position.timestamp_ns.

## Successful Response

```protobuf
timestamp: 1790611197799
data: "[\"2026-09-28T15:59:57.799360275\",{\"tx_hash\":\"0x70f7f7919fbb85174223f6c5b957964813a9673f2ccb1d2f85d5a91e8a939c17\",\"signed_actions\":[{\"signature\":{\"r\":\"0x92c15a2df3a6cbe1464903a31abbdcca1ec54edcb6aee1ee0f8805beda05f289\",\"s\":\"0x792fc9397bd81cb8b80f481d8649c4cc1ae683b3113c586e9e8ac98d1fe58280\",\"v\":28},\"action\":{\"type\":\"noop\"},\"nonce\":1790611116331,\"expiresAfter\":1790611227625}]}]"
timestamp_ns: 1790611197799360275
```

## Error Responses

### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or the request sets position.block_number or any filter.

### Not found

- Code: `NOT_FOUND`
- Description: The cursor is before the earliest retained record, or the selected endpoint does not serve the mempool feed.

### Message too large

- Code: `RESOURCE_EXHAUSTED`
- Description: The record exceeded the client receive limit. Raise the client inbound message limit.

### Deadline exceeded

- Code: `DEADLINE_EXCEEDED`
- Description: An unpositioned call waited longer than the client deadline for the next client block.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## Addressing records

Several client blocks often share one millisecond, so `position.timestamp` returns the first record of that millisecond. `position.timestamp_ns` addresses each record exactly. To step to the next record, call again with the last `Record.timestamp_ns` plus 1.

A timestamp before the earliest retained record returns `NOT_FOUND`. `NOT_FOUND` also means the selected endpoint does not serve the mempool feed; check `ListFeeds` for `mempool-txs`.

`GetMempoolTxs` returns the same format as `StreamMempoolTxs`. See the [StreamMempoolTxs documentation](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs#record-format) for the decoded `Record.data` fields.

## Current Limitations

- **Pre-consensus only**: Records carry requests without responses, and inclusion is not guaranteed
- **Time addressing only**: `position.block_number` and filters are rejected
- **Replay History**: Available replay history varies by endpoint. A cursor outside retained history returns `NOT_FOUND`

## Resources

- **[StreamMempoolTxs](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs)** - Record format, ordering, and streaming recovery
- **[ListFeeds](https://www.dwellir.com/docs/hyperliquid/list_feeds)** - Feed inventory and accepted cursor kinds

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetMiscEvents - Get Miscellaneous Event Data

# GetMiscEvents - Get Miscellaneous Event Data

Retrieve miscellaneous events at a specific position from the Hyperliquid L1 Gateway.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetMiscEvents` is essential for:

- **Reconciliation** - Verify deposits, withdrawals, and transfers at a specific block
- **Historical Analysis** - Retrieve misc events for reporting or accounting
- **Auditing** - Confirm staking and validator reward activity at a specific block
- **Debugging** - Investigate specific events during development

Method signature

```protobuf
rpc GetMiscEvents(GetRequest) returns (Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`; explicit zero is invalid. A positioned call returns the selected envelope. An empty `GetRequest` waits for the next miscellaneous-event record written after the call begins, so set a deadline.

```protobuf
position: {
  timestamp: 1785736814057
}
filter: {
  fields: {
    field: "users"
    op: FILTER_OP_IN
    values: "0x1111111111111111111111111111111111111111"
  }
}
```

Miscellaneous events accept a `users` filter. User matching is case-insensitive, and values within the field use OR semantics. This feed does not accept `coins`. A zero-match unary request returns the selected `Record` with `data` containing `events: []`. The record also exposes optional `block_number` and `timestamp` cursors. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`. See [StreamMiscEvents user filtering](https://www.dwellir.com/docs/hyperliquid/stream_misc_events#user-filtering) for which addresses match each event kind.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to wait for the next written record.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users constraints. Values within the field OR together. This feed does not accept coins.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name. This feed accepts users only.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"users","op":"FILTER_OP_IN","values":["0x1111111111111111111111111111111111111111"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetMiscEvents
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the misc_events_by_block, with non-matching events removed when a filter is applied.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Position ahead of head

- Code: `OUT_OF_RANGE`
- Description: The requested block is above the feed's current head and may become available later.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to target the latest data.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to target the latest data.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetMiscEvents
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockMiscEvents wrapper.

### Successful Response

```protobuf
message BlockMiscEvents {
  bytes data = 1;
}
```

```protobuf
rpc GetMiscEvents(Position) returns (BlockMiscEvents) {}
```

V2 accepts `block_height` or Unix-millisecond `timestamp_ms` and returns the source JSON in `BlockMiscEvents.data`.

## Common Use Cases

For V3, select a record with `GetRequest.position.block_number`, decode `Record.data`, and branch on each event's `inner` discriminator. Repeat positioned unary calls when reconciling a bounded block range.

### 1. Inspect a Single Block

```python
def get_block_misc_events(client, metadata, block_height):
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetMiscEvents(request, metadata=metadata)
    block = json.loads(response.data)

    for event in block.get('events', []):
        kind = next(iter(event['inner']))  # the discriminator key
        print(kind, event['hash'])
```

### 2. Replay a Block Range

```python
def replay_misc_events(client, metadata, start_block, end_block):
    for block_height in range(start_block, end_block + 1):
        request = hyperliquid_pb2.Position(block_height=block_height)
        response = client.GetMiscEvents(request, metadata=metadata)
        process(json.loads(response.data))
```

`GetMiscEvents` returns the same format as `StreamMiscEvents`. See the [StreamMiscEvents documentation](https://www.dwellir.com/docs/hyperliquid/stream_misc_events) for the complete field reference, including the [block envelope](https://www.dwellir.com/docs/hyperliquid/stream_misc_events#full-misc-events-spec) and per-[event type](https://www.dwellir.com/docs/hyperliquid/stream_misc_events#event-types) shapes.

## Best Practices

1. **Position Selection**: Use the exact sequential block cursor for precise queries; timestamp lookups may resolve to different blocks across requests
2. **Defensive Parsing**: Branch on the key inside `inner` (and `delta.type` for `LedgerUpdate`) and handle unknown types gracefully
3. **Data Validation**: Always validate JSON structure and handle the common empty `events` array
4. **Error Recovery**: Implement retry logic with exponential backoff
5. **Resource Management**: Close gRPC connections properly to avoid resource leaks

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[StreamMiscEvents Documentation](https://www.dwellir.com/docs/hyperliquid/stream_misc_events)** - Full misc event specification and streaming examples
- **[Hyperliquid L1 Data Schemas](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/nodes/l1-data-schemas)** - Authoritative upstream event schema reference

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetOrderBookSnapshot - Get Order Book Data

# GetOrderBookSnapshot - Get Order Book Data

Retrieve a full order book snapshot at a specific point in time from the Hyperliquid L1 Gateway. Returns every individual open order across all markets with complete metadata including order IDs, timestamps, trigger conditions, and child orders.

This RPC is the public method for retrieving a generated order-book snapshot. Snapshots intentionally do not appear in `ListFeeds`. Snapshot availability and maximum response size vary by endpoint. Oversized responses return `RESOURCE_EXHAUSTED`.

Large snapshots can exceed a gRPC client inbound message limit even when the endpoint can deliver the response. Client receive limits are separate from endpoint delivery limits. Configure them per client and workload; there is no universal fixed size that fits every snapshot.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetOrderBookSnapshot` is essential for:

- **Market Microstructure Analysis** - Access every individual order with full metadata
- **Queue Position Tracking** - See exact order placement timestamps and sizes
- **Whale Watching** - Monitor large orders with their original sizes and trigger conditions
- **Trading Strategies** - Analyze order distribution, TP/SL clustering, and trigger order density
- **Risk Management** - Assess market impact with individual order granularity

Method signature

```protobuf
rpc GetOrderbookSnapshot(GetRequest) returns (Record) {}
```

The V3 RPC spelling is `GetOrderbookSnapshot`; this established page keeps the V2 `GetOrderBookSnapshot` URL and naming for compatibility. V3 accepts only an inclusive Unix-millisecond `position.timestamp`; `position.block_number`, filters, and explicit zero return `INVALID_ARGUMENT`. A positioned lookup returns the snapshot covering the requested timestamp. An empty `GetRequest` returns the latest existing snapshot rather than waiting for the next one.

```protobuf
position: {
  timestamp: 1785736814057
}
```

In the V3 `Record`, `block_number` and `timestamp` are typed transport cursors. They are outside the snapshot JSON. Decoded `Record.data` is the snapshot's top-level array of `[coin, [bids, asks]]` tuples, and each side contains order objects. A timestamp outside retained history returns `NOT_FOUND`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond lookup cursor. Returns the snapshot covering this timestamp. Omit it to return the latest existing snapshot.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"timestamp":"1785736814057"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetOrderbookSnapshot
```

### Response Fields

- `block_number` (`optional int64, optional`): Typed transport cursor for the sequential Hyperliquid block number; it is outside decoded Record.data and is never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Typed transport cursor for the snapshot block time in Unix milliseconds; it is outside decoded Record.data.
- `data` (`bytes, required`): Record.data decodes directly to the top-level [coin, [bids, asks]] array.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "[[\"BTC\",[[{\"coin\":\"BTC\",\"side\":\"B\",\"limitPx\":\"114250.0\",\"sz\":\"0.25\",\"oid\":123456789,\"timestamp\":1785736813000,\"triggerCondition\":\"N/A\",\"isTrigger\":false,\"triggerPx\":\"0.0\",\"children\":[],\"isPositionTpsl\":false,\"reduceOnly\":false,\"orderType\":\"Limit\",\"origSz\":\"0.25\",\"tif\":\"Gtc\",\"cloid\":null}],[]]]]"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: The timestamp cursor is zero, a block-number cursor or filter was supplied, or the request is otherwise malformed.

#### Not found

- Code: `NOT_FOUND`
- Description: Snapshot availability varies by endpoint, and the requested timestamp is outside retained history.

#### Snapshot exceeds a delivery limit

- Code: `RESOURCE_EXHAUSTED`
- Description: Snapshot availability and maximum response size vary by endpoint. Oversized responses return RESOURCE_EXHAUSTED.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond timestamp. Zero selects the latest available snapshot.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"timestamp_ms":"1785736814057"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetOrderBookSnapshot
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 OrderBookSnapshot wrapper.

### Successful Response

```protobuf
message OrderBookSnapshot {
  bytes data = 1;
}
```

```protobuf
rpc GetOrderBookSnapshot(Timestamp) returns (OrderBookSnapshot) {}
```

V2 accepts the inclusive Unix-millisecond field `timestamp_ms`. Its zero value selects the latest available snapshot.

Unlike V3, V2 keeps transport metadata inside the JSON carried by `OrderBookSnapshot.data`:

```json
{
  "block": "1058646974",
  "timestamp": 1785736814057,
  "data": [
    ["BTC", [[], []]]
  ]
}
```

The inner `data` array uses the same `[coin, [bids, asks]]` snapshot shape.

## Response Examples

### Simple Limit Order (Bid)

```json
{
  "coin": "0G",
  "side": "B",
  "limitPx": "0.59341",
  "sz": "52.0",
  "oid": 333003526755,
  "timestamp": 1772276628506,
  "triggerCondition": "N/A",
  "isTrigger": false,
  "triggerPx": "0.0",
  "children": [],
  "isPositionTpsl": false,
  "reduceOnly": false,
  "orderType": "Limit",
  "origSz": "52.0",
  "tif": "Alo",
  "cloid": "0x00000000000000000000000000000318"
}
```

### Order with TP/SL Children

A parent limit order can have up to 2 child orders (stop-loss and/or take-profit) attached:

```json
{
  "coin": "AAVE",
  "side": "B",
  "limitPx": "104.6",
  "sz": "1.94",
  "oid": 332954766819,
  "timestamp": 1772272640873,
  "triggerCondition": "N/A",
  "isTrigger": false,
  "triggerPx": "0.0",
  "children": [
    {
      "coin": "AAVE",
      "side": "A",
      "limitPx": "94.3",
      "sz": "1.94",
      "oid": 332954766820,
      "timestamp": 1772272640873,
      "triggerCondition": "Price below 102.5",
      "isTrigger": true,
      "triggerPx": "102.5",
      "children": [],
      "isPositionTpsl": false,
      "reduceOnly": true,
      "orderType": "Stop Market",
      "origSz": "1.94",
      "tif": null,
      "cloid": null
    },
    {
      "coin": "AAVE",
      "side": "A",
      "limitPx": "102.0",
      "sz": "1.94",
      "oid": 332954766821,
      "timestamp": 1772272640873,
      "triggerCondition": "Price above 110.87",
      "isTrigger": true,
      "triggerPx": "110.87",
      "children": [],
      "isPositionTpsl": false,
      "reduceOnly": true,
      "orderType": "Take Profit Market",
      "origSz": "1.94",
      "tif": null,
      "cloid": null
    }
  ],
  "isPositionTpsl": false,
  "reduceOnly": false,
  "orderType": "Limit",
  "origSz": "1.94",
  "tif": "Gtc",
  "cloid": null
}
```

### Triggered Order

An order where the trigger condition has already been met and the order is now active:

```json
{
  "coin": "ARB",
  "side": "A",
  "limitPx": "0.1099",
  "sz": "601.7",
  "oid": 331886608601,
  "timestamp": 1772189655929,
  "triggerCondition": "Triggered",
  "isTrigger": false,
  "triggerPx": "0.0",
  "children": [],
  "isPositionTpsl": false,
  "reduceOnly": true,
  "orderType": "Take Profit Limit",
  "origSz": "601.7",
  "tif": "Gtc",
  "cloid": null
}
```

## Important Notes

- **Individual orders, not aggregated levels.** Each entry is an individual order with full metadata (order ID, timestamp, trigger info, children, etc.).
- **Bids are sorted by price descending** (highest price first). **Asks are sorted by price ascending** (lowest price first).
- **Children are never nested.** Child orders always have an empty `children` array.
- **Trigger orders** (`isTrigger: true`) have `tif: null` and meaningful `triggerCondition` / `triggerPx` values.
- **Once triggered**, the order becomes `isTrigger: false`, `triggerCondition: "Triggered"`, `triggerPx: "0.0"`, and receives a `tif` value (typically `"Gtc"`).

## Best Practices

1. **Message Size Configuration**: Configure the client inbound message limit per client and workload, and account separately for endpoint delivery limits; oversized responses return `RESOURCE_EXHAUSTED`
2. **Timeout**: Use a generous timeout (60-120 seconds) for the RPC call due to the large response
3. **Data Validation**: Always validate JSON structure before processing
4. **Error Recovery**: Implement retry logic with exponential backoff
5. **Resource Management**: Close gRPC connections properly to avoid resource leaks
6. **Streaming Alternative**: For continuous updates, consider using `StreamOrderbookSnapshots` instead

## Current Limitations

- **Replay History**: Available snapshot history varies by endpoint; a timestamp outside retained history returns `NOT_FOUND`
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service
- **Availability**: Snapshot availability and maximum response size vary by endpoint; oversized responses return `RESOURCE_EXHAUSTED`

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[Copy Trading Bot](https://github.com/dwellir-public/gRPC-code-examples/tree/main/copy-trading-bot)** - Production-ready trading bot example
- **[Pricing](https://www.dwellir.com/docs/hyperliquid/pricing)** - Dedicated node cluster pricing details

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetOrderStatuses - Get Order Status Data

# GetOrderStatuses - Get Order Status Data

Retrieve order status events at a specific position from the Hyperliquid L1 Gateway.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetOrderStatuses` is essential for:

- **Order Reconciliation** - Verify order lifecycle events at a specific block
- **Rejection Analysis** - Retrieve and classify rejections at a point in time
- **Auditing** - Confirm status transitions at specific blocks
- **Debugging** - Investigate specific order outcomes during development

Method signature

```protobuf
rpc GetOrderStatuses(GetRequest) returns (Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`; explicit zero is invalid. A positioned call returns the selected envelope. An empty `GetRequest` waits for the next status record written after the call begins, so set a deadline.

```protobuf
filter: {
  fields: {
    field: "coins"
    op: FILTER_OP_IN
    values: "BTC"
  }
}
```

Order statuses accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. A zero-match unary request returns the selected `Record` with `data` containing `events: []`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to wait for the next written record.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetOrderStatuses
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_order_statuses_by_block, with non-matching events removed when a filter is applied.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Position ahead of head

- Code: `OUT_OF_RANGE`
- Description: The requested block is above the feed's current head and may become available later.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to target the latest data.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to target the latest data.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetOrderStatuses
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockOrderStatuses wrapper.

### Successful Response

```protobuf
message BlockOrderStatuses {
  bytes data = 1;
}
```

```protobuf
rpc GetOrderStatuses(Position) returns (BlockOrderStatuses) {}
```

V2 accepts `block_height` or Unix-millisecond `timestamp_ms` and returns the source JSON in `BlockOrderStatuses.data`.

## Common Use Cases

For V3, select each record with `GetRequest.position.block_number`, decode `Record.data`, and inspect the `events` array. This supports single-block inspection and bounded searches for rejection statuses.

### 1. Inspect a Single Block

```python
def get_block_statuses(client, metadata, block_height):
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetOrderStatuses(request, metadata=metadata)
    block = json.loads(response.data)

    for event in block.get('events', []):
        print(event['status'], event['order']['coin'], event['order']['oid'])
```

### 2. Find Rejections in a Block Range

```python
REJECTIONS = {
    'badAloPxRejected', 'insufficientSpotBalanceRejected', 'iocCancelRejected',
    'minTradeNtlRejected', 'perpMarginRejected', 'reduceOnlyRejected',
}

def find_rejections(client, metadata, start_block, end_block):
    rejected = []
    for block_height in range(start_block, end_block + 1):
        request = hyperliquid_pb2.Position(block_height=block_height)
        response = client.GetOrderStatuses(request, metadata=metadata)
        block = json.loads(response.data)
        for event in block.get('events', []):
            if event['status'] in REJECTIONS:
                rejected.append(event)
    return rejected
```

`GetOrderStatuses` returns the same format as `StreamOrderStatuses`. See the [StreamOrderStatuses documentation](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses) for the complete field reference, including [status values](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses#status-values) and the [order object](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses#order-object).

## Best Practices

1. **Position Selection**: Use the exact sequential block cursor for precise queries; timestamp lookups may resolve to different blocks across requests
2. **Stable Keys**: Index per-order state on `(coin, oid)`, never on `oid` alone
3. **Defensive Parsing**: Handle nullable `hash` and `builder` and the non-exhaustive `status` set
4. **Error Recovery**: Implement retry logic with exponential backoff
5. **Resource Management**: Close gRPC connections properly to avoid resource leaks

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[StreamOrderStatuses Documentation](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses)** - Full order status specification and streaming examples
- **[Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)** - Historical `node_order_statuses_by_block` downloads

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetRawBookDiffs - Get Book Diff Data

# GetRawBookDiffs - Get Book Diff Data

Retrieve order book diffs at a specific position from the Hyperliquid L1 Gateway.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetRawBookDiffs` is essential for:

- **Targeted Reconstruction** - Pull the book changes for a specific block
- **Historical Analysis** - Retrieve diffs for backtesting or reporting
- **Auditing** - Verify resting-book changes at a specific block
- **Debugging** - Investigate specific book transitions during development

Method signature

```protobuf
rpc GetRawBookDiffs(GetRequest) returns (Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`; explicit zero is invalid. A positioned call returns the selected envelope. An empty `GetRequest` waits for the next diff record written after the call begins, so set a deadline.

```protobuf
filter: {
  fields: {
    field: "users"
    op: FILTER_OP_IN
    values: "0x1111111111111111111111111111111111111111"
  }
}
```

Raw book diffs accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. A zero-match unary request returns the selected `Record` with `data` containing `events: []`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

Seed any reconstruction from a snapshot or another known state before applying diffs.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to wait for the next written record.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetRawBookDiffs
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_raw_book_diffs_by_block, with non-matching events removed when a filter is applied.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Position ahead of head

- Code: `OUT_OF_RANGE`
- Description: The requested block is above the feed's current head and may become available later.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to target the latest data.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to target the latest data.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetRawBookDiffs
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockRawBookDiffs wrapper.

### Successful Response

```protobuf
message BlockRawBookDiffs {
  bytes data = 1;
}
```

```protobuf
rpc GetRawBookDiffs(Position) returns (BlockRawBookDiffs) {}
```

V2 accepts `block_height` or Unix-millisecond `timestamp_ms` and returns the source JSON in `BlockRawBookDiffs.data`.

## Common Use Cases

For V3, select each record with `GetRequest.position.block_number`, decode `Record.data`, and apply the entries in its `events` array. Repeat positioned unary calls when reconciling a bounded block range.

### 1. Inspect a Single Block

```python
def get_block_diffs(client, metadata, block_height):
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetRawBookDiffs(request, metadata=metadata)
    block = json.loads(response.data)

    for event in block.get('events', []):
        print(event['coin'], event['oid'], event['raw_book_diff'])
```

### 2. Replay a Block Range

```python
def replay_diffs(client, metadata, start_block, end_block):
    for block_height in range(start_block, end_block + 1):
        request = hyperliquid_pb2.Position(block_height=block_height)
        response = client.GetRawBookDiffs(request, metadata=metadata)
        apply(json.loads(response.data))
```

`GetRawBookDiffs` returns the same format as `StreamRawBookDiffs`. See the [StreamRawBookDiffs documentation](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs) for the complete field reference, including the three [`raw_book_diff` shapes](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs#full-book-diff-spec) and [order-identifier keying](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs#order-identifiers).

## Best Practices

1. **Position Selection**: Use the exact sequential block cursor for precise queries; timestamp lookups may resolve to different blocks across requests
2. **Stable Keys**: Index resting orders on `(coin, oid)`, never on `oid` alone
3. **Data Validation**: Always validate JSON structure and branch on the `raw_book_diff` shape
4. **Error Recovery**: Implement retry logic with exponential backoff
5. **Resource Management**: Close gRPC connections properly to avoid resource leaks

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[StreamRawBookDiffs Documentation](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs)** - Full book diff specification and streaming examples
- **[Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)** - Historical `node_raw_book_diffs_by_block` downloads

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## GetTwapStatuses - Get TWAP Status Data

# GetTwapStatuses - Get TWAP Status Data

Retrieve TWAP order lifecycle events at a specific position from the Hyperliquid L1 Gateway.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`GetTwapStatuses` is essential for:

- **TWAP Reconciliation** - Verify TWAP lifecycle events at a specific block
- **Execution Analysis** - Inspect executed size and notional for a TWAP state update
- **Auditing** - Confirm TWAP status transitions at specific blocks
- **Debugging** - Investigate specific TWAP order outcomes during development

Use the unary method when you already know the block or timestamp you want to inspect. For continuous ingestion, use [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses) and persist your last processed `block_number`.

Method signature

```protobuf
rpc GetTwapStatuses(GetRequest) returns (Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`; explicit zero is invalid. A positioned call returns the selected envelope. An empty `GetRequest` waits for the next TWAP-status record written after the call begins, so set a deadline.

```protobuf
filter: {
  fields: {
    field: "users"
    op: FILTER_OP_IN
    values: "0x1111111111111111111111111111111111111111"
  }
}
```

TWAP statuses accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. A zero-match unary request returns the selected `Record` with `data` containing `events: []`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to wait for the next written record.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/GetTwapStatuses
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_twap_statuses_by_block, with non-matching events removed when a filter is applied.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Position ahead of head

- Code: `OUT_OF_RANGE`
- Description: The requested block is above the feed's current head and may become available later.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to target the latest data.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to target the latest data.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/GetTwapStatuses
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockTwapStatuses wrapper.

### Successful Response

```protobuf
message BlockTwapStatuses {
  bytes data = 1;
}
```

```protobuf
rpc GetTwapStatuses(Position) returns (BlockTwapStatuses) {}
```

V2 accepts `block_height` or Unix-millisecond `timestamp_ms` and returns the source JSON in `BlockTwapStatuses.data`. An empty `Position` targets the latest available TWAP status envelope.

## Response Shape

Both versions return one JSON-encoded block envelope in a `data` field.

V3 returns a `Record`; decode `Record.data`. Its optional `block_number` and `timestamp` fields are typed transport cursors.

V2 returns the envelope in `BlockTwapStatuses.data`:

```protobuf
message BlockTwapStatuses {
  // JSON-encoded block envelope from "node_twap_statuses_by_block".
  bytes data = 1;
}
```

The decoded JSON has the same shape as [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses):

```json
{
  "local_time": "2026-07-03T06:00:14.508835456",
  "block_time": "2026-07-03T06:00:14.057132297",
  "block_number": 1058646974,
  "events": [
    {
      "time": "2026-07-03T06:00:14.057132297",
      "twap_id": 1999381,
      "state": {
        "coin": "kPEPE",
        "user": "0x2ee1f7d5650bb9bc08e101dc5ab2300b4f5c1be9",
        "side": "B",
        "sz": "555555.0",
        "executedSz": "555555.0",
        "executedNtl": "1371.51378",
        "minutes": 5,
        "reduceOnly": false,
        "randomize": false,
        "timestamp": 1783058112775
      },
      "status": "finished"
    }
  ]
}
```

Most queried blocks can return an empty `events` array. That means no TWAP lifecycle update was recorded in that block; the block envelope itself is still valid.

## Common Use Cases

For V3, select each record with `GetRequest.position.block_number`, decode `Record.data`, and process its `events` array. Index lifecycle state by `twap_id`; calculate progress from `executedSz / sz`, and treat both unknown string statuses and object status payloads defensively.

### 1. Inspect a Single Block

```python
def get_block_twap_statuses(client, metadata, block_height):
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetTwapStatuses(request, metadata=metadata)
    block = json.loads(response.data)

    for event in block.get('events', []):
        state = event['state']
        print(event['status'], event['twap_id'], state['coin'], state['executedSz'])
```

### 2. Calculate Execution Progress

```python
from decimal import Decimal

def twap_progress(event):
    state = event['state']
    target = Decimal(state['sz'])
    executed = Decimal(state['executedSz'])
    return executed / target if target else Decimal('0')
```

### 3. Replay TWAP Lifecycle Updates

```python
def replay_twap_statuses(client, metadata, start_block, end_block):
    by_twap_id = {}

    for block_height in range(start_block, end_block + 1):
        request = hyperliquid_pb2.Position(block_height=block_height)
        response = client.GetTwapStatuses(request, metadata=metadata)
        block = json.loads(response.data)

        for event in block.get('events', []):
            by_twap_id[event['twap_id']] = event

    return by_twap_id
```

### 4. Find Terminal TWAP Events

```python
def get_terminal_twaps(client, metadata, block_height):
    request = hyperliquid_pb2.Position(block_height=block_height)
    response = client.GetTwapStatuses(request, metadata=metadata)
    block = json.loads(response.data)

    return [
        event for event in block.get('events', [])
        if event['status'] in ('finished', 'terminated') or isinstance(event['status'], dict)
    ]
```

`GetTwapStatuses` returns the same format as `StreamTwapStatuses`. See the [StreamTwapStatuses documentation](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses) for the complete field reference, including the [TWAP state object](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses#twap-state-object) and [status values](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses#status-values).

## V2 positioning semantics

`Position` accepts either `block_height` or `timestamp_ms`. Use one field at a time:

- `block_height` fetches the block-envelope record at that exact block.
- `timestamp_ms` resolves to the feed position at or after the timestamp.
- Empty `Position` targets the latest available TWAP status envelope.

For deterministic reconciliation, prefer `block_height`. Timestamp-based lookups are useful when your upstream system stores wall-clock times but not Hyperliquid block numbers.

## Best Practices

1. **Position Selection**: Use the exact sequential block cursor for precise queries; timestamp lookups may resolve to different blocks across requests
2. **Stable Keys**: Index per-TWAP state on `twap_id`
3. **Defensive Parsing**: Handle an empty `events` array, unknown future string statuses, and object status payloads
4. **Numeric Precision**: Parse size and notional fields as decimals, not floats
5. **Action Correlation**: Use [GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block) or [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) when you need the original signed `twapOrder` or `twapCancel` action
6. **Resource Management**: Close gRPC connections properly to avoid resource leaks

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Schema Coverage**: The upstream lifecycle set can grow; treat documented statuses as examples, not an exhaustive list
- **Rate Limits**: Be mindful of request frequency to avoid overwhelming the service

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[StreamTwapStatuses Documentation](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses)** - Full TWAP status specification and streaming examples
- **[twapOrder Action Type](https://www.dwellir.com/docs/hyperliquid/twapOrder)** - TWAP order submission payloads in StreamBlocks
- **[twapCancel Action Type](https://www.dwellir.com/docs/hyperliquid/twapCancel)** - TWAP cancellation payloads in StreamBlocks

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## Hyperliquid gRPC API

# Hyperliquid gRPC API

For quiet filtered streams, proxy timeouts, recovery, and usage, see [streaming troubleshooting](https://www.dwellir.com/docs/hyperliquid/troubleshooting).

Dwellir's Hyperliquid gRPC endpoint exposes the V3 raw-feed and typed market-streaming services alongside the V2 compatibility service. Use V3 for new integrations. Existing V2 clients can continue using their generated V2 stubs and the established method URLs in this reference.

## Pricing and access

The gRPC add-on costs $299/month on an API plan, plus metered usage: each streamed message costs 1 API credit. The [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster) starts at $4,000/month and 2 dedicated backend nodes, and includes both add-ons with unmetered access.

The gRPC API is the live transport for raw node feeds and derived V3 market views. Start with [How Hyperliquid works](https://www.dwellir.com/docs/hyperliquid#how-hyperliquid-works) for the relationship between node files, order books, indexed products, and archives.

## Versions and services

| Version | Service                                          | Surface                                                                         |
| ------- | ------------------------------------------------ | ------------------------------------------------------------------------------- |
| V3      | `hyperliquid_l1_gateway.v3.HyperliquidL1Gateway` | Feed discovery plus eight raw streams and eight raw unary lookups               |
| V3      | `hyperliquid_l1_gateway.v3.MarketStreaming`      | Fourteen typed, live market streams                                             |
| V2      | `hyperliquid_l1_gateway.v2.HyperliquidL1Gateway` | Compatibility surface for the fourteen established raw stream and unary methods |

Download the published contracts as [`v3.proto`](https://www.dwellir.com/docs/hyperliquid/v3.proto) and [`v2.proto`](https://www.dwellir.com/docs/hyperliquid/v2.proto). Regenerate client stubs when you change versions; the V2 and V3 packages, request messages, and response messages are different.

```bash
curl -fsSLo v3.proto https://www.dwellir.com/docs/hyperliquid/grpc/v3.proto
```

## Authentication

Connect over TLS and pass the API key in the `x-api-key` metadata header. Keep the endpoint and credential outside source control:

```bash
grpcurl -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/ListFeeds
```

## V3 raw-feed service

The V3 raw service declares seventeen RPCs: `ListFeeds`, eight server streams, and eight unary lookups.

| Feed concept                       | Stream                                                                   | Unary                                                             | Source                         |
| ---------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------- | ------------------------------ |
| Configured-feed discovery          | [ListFeeds](https://www.dwellir.com/docs/hyperliquid/list_feeds)                                | -                                                                 | Gateway registry               |
| Blocks                             | [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks)                          | [GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block)                           | `replica_cmds`                 |
| Fills                              | [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills)                            | [GetFills](https://www.dwellir.com/docs/hyperliquid/get_fills)                           | `node_fills_by_block`          |
| Raw book diffs                     | [StreamRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs)            | [GetRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/get_raw_book_diffs)           | `node_raw_book_diffs_by_block` |
| Order statuses                     | [StreamOrderStatuses](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses)           | [GetOrderStatuses](https://www.dwellir.com/docs/hyperliquid/get_order_statuses)          | `node_order_statuses_by_block` |
| Miscellaneous events               | [StreamMiscEvents](https://www.dwellir.com/docs/hyperliquid/stream_misc_events)                 | [GetMiscEvents](https://www.dwellir.com/docs/hyperliquid/get_misc_events)                | `misc_events_by_block`         |
| TWAP statuses                      | [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses)             | [GetTwapStatuses](https://www.dwellir.com/docs/hyperliquid/get_twap_statuses)            | `node_twap_statuses_by_block`  |
| Pre-consensus mempool transactions | [StreamMempoolTxs](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs)                 | [GetMempoolTxs](https://www.dwellir.com/docs/hyperliquid/get_mempool_txs)                | `mempool_txs`                  |
| Generated order-book snapshots     | [StreamOrderbookSnapshots](https://www.dwellir.com/docs/hyperliquid/stream_orderbook_snapshots) | [GetOrderbookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot) | Generated snapshot output      |

`StreamOrderbookSnapshots` and `GetOrderbookSnapshot` are the public methods for generated order-book snapshots. Snapshots intentionally sit outside the raw-feed registry, so absence from `ListFeeds` does not describe their status. Snapshot availability and maximum response size vary by endpoint. Oversized responses return `RESOURCE_EXHAUSTED`.

The mempool feed carries signed transaction requests the node received before block inclusion. They are not guaranteed to land in a block. Mempool records have no block number, so the feed is positioned by receive time only and is not filterable. V2 has no mempool methods.

### Shared request contract

All raw streams accept `StreamRequest`; all raw unary methods accept `GetRequest`.

```protobuf
message Position {
  oneof position {
    int64 timestamp = 1;
    int64 block_number = 2;
    int64 timestamp_ns = 3;
  }
}

message Filter {
  repeated FieldFilter fields = 1;
}

message FieldFilter {
  string field = 1;
  FilterOp op = 2;
  repeated string values = 3;
}

message StreamRequest {
  Position position = 1;
  Filter filter = 2;
  Progress progress = 3; // unset = no progress frames
}

message Progress {
  uint32 interval_ms = 1; // 0 = feed default
}

message GetRequest {
  Position position = 1;
  Filter filter = 2;
}
```

`Position` is inclusive. A positioned stream replays the selected record and all subsequent retained records, then tails live data. A positioned unary call returns the record at the requested block number or the nearest record at or after a timestamp.

Leave `position` unset to tail new records in a raw stream. For the seven registry feeds, an unpositioned unary call waits for the next record written after the call begins; it does not return the most recently stored record. The snapshot contract is different: an unpositioned snapshot stream sends the latest snapshot and then newer snapshots, while an unpositioned `GetOrderbookSnapshot` returns the latest existing snapshot.

V3 uses `block_number` and `timestamp` in Unix milliseconds. V2 uses `block_height` and `timestamp_ms`. The mempool feed accepts `timestamp` and `timestamp_ns` (Unix nanoseconds) instead of `block_number`; every other raw feed rejects `timestamp_ns`. `ListFeeds.position_kinds` lists the cursor kinds each feed accepts, and any other kind returns `INVALID_ARGUMENT`. In V3, explicitly setting any cursor to `0` returns `INVALID_ARGUMENT`; omit `position` for the unpositioned behavior. A `Record.block_number` is the sequential Hyperliquid block number and is never the potentially skipping HyperBFT consensus value in `abci_block.round`.

### Filtering

The fills, raw-book-diffs, order-statuses, and TWAP-statuses feeds accept `users` and `coins` field filters. Miscellaneous events accept `users` only. Blocks, mempool transactions, and order-book snapshots do not accept filters. Use `ListFeeds.filter_fields` as the deployed capability source for registry feeds.

- Constraints for separate fields use AND semantics.
- Values within one field use OR semantics.
- User addresses match case-insensitively.
- Coin identifiers match case-sensitively.
- `FILTER_OP_UNSPECIFIED` is treated as `FILTER_OP_IN`.
- Unknown or duplicate fields, empty names, and empty value lists return `INVALID_ARGUMENT`.
- An unsupported operator returns `UNIMPLEMENTED`.

Filtering preserves the raw block envelope and removes non-matching entries from its `events` array. A streaming filter skips records with zero matching events, so a tightly filtered stream can be silent for minutes; opt in to [progress frames](#progress-frames) to keep it open and advance its resume cursor. A unary filter still returns the selected `Record`, with `data` containing an empty `events` array when no events match.

### Raw response and recovery

```protobuf
message Record {
  optional int64 block_number = 1;
  optional int64 timestamp = 2;
  bytes data = 3;
  optional int64 timestamp_ns = 4;
  StreamProgress progress = 5; // progress frames only
}
```

`data` is the source record as bytes when no filter is applied. Cursor fields are optional because metadata extraction is best-effort; resume only from a cursor that is present. Mempool records always leave `block_number` unset; their `timestamp` is the receive time, and `timestamp_ns` carries the same time at nanosecond precision. Only the mempool feed sets `timestamp_ns`, and it is the exact resume cursor there because several mempool records can share one millisecond.

Streams carry no heartbeat frames unless they opt in to [progress frames](#progress-frames). `UNAVAILABLE` means no new records arrived before the stream timeout, or the stream failed mid-stream on the server; nothing before it was skipped. `DEADLINE_EXCEEDED` means the stream could not deliver records in time because the client read too slowly or stopped reading. `DATA_LOSS` means the stream lost records, for example because it fell behind the live feed, and it ends before sending any cursor past them. After any of these, reconnect from the last cursor received and the replay re-reads the gap. The one exception: a replay positioned by `timestamp` can skip a stored record whose timestamp does not parse, without an error.

A mempool record can exceed the default 4 MiB gRPC receive limit, so raise the client inbound message limit for that feed. A record over the limit fails the call with `RESOURCE_EXHAUSTED` from the client library; retrying does not fix it.

Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`; use the [historical-data products](https://www.dwellir.com/docs/hyperliquid/historical-data) for archival data. A `RESOURCE_EXHAUSTED` from the server means replay capacity is temporarily unavailable; retry with backoff. This also applies to filtered replay.

### Progress frames

A raw stream can opt in to progress frames, an application-level heartbeat: in-band messages sent after each interval of silence. They keep a quiet filtered stream open through proxies with per-stream idle timers, which HTTP/2 keepalive pings do not reset, and advance the resume cursor through blocks the filter removed.

The blocks, fills, misc-events, order-statuses, raw-book-diffs, and TWAP-statuses feeds support them. `ListFeeds` reports support and interval bounds per feed in `FeedInfo.progress`.

- **Opt-in.** Set `StreamRequest.progress.interval_ms`, the longest silence before a progress frame. `0` selects the feed default, currently 20 seconds within bounds of 10 to 60 seconds. An interval outside the bounds, or `progress` on `StreamOrderbookSnapshots` or a feed without `FeedInfo.progress`, returns `INVALID_ARGUMENT`.
- **Acknowledgement.** The response headers carry `x-progress-interval-ms` with the applied interval. Through Dwellir's endpoint they arrive with the first message, not when the stream opens. If the header is absent, the request was not honored.
- **Frame shape.** A progress frame sets `Record.progress` and leaves `data`, `block_number`, and `timestamp` unset. Check `progress` before treating a record as data.
- **`scanned_through`.** The inclusive cursor of the newest record the stream has examined, sent or removed by the filter. It is unset until the stream has examined a record. `StreamProgress.timestamp` is the source time at that cursor in Unix milliseconds.
- **Resume.** A set `scanned_through` is a valid resume `Position` with the same delivery guarantee as a data record's cursor. Resume is inclusive, so deduplicate on the cursor. Do not resume at `scanned_through + 1`: a block start above the latest block returns `INVALID_ARGUMENT`.
- **Stall signal.** An unchanged `scanned_through` across frames means the feed is not advancing. Progress frames do not reset the stream timeout: after 60 seconds without new records, the stream closes with `UNAVAILABLE` and the message `stream idle`.
- **Usage.** Progress frames count toward metered usage.

Open a filtered stream with progress frames every 15 seconds:

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"filter":{"fields":[{"field":"users","values":["0x1234567890abcdef1234567890abcdef12345678"]}]},"progress":{"interval_ms":15000}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamFills
```

While the user has no fills, the stream sends progress frames such as:

```protobuf
progress: {
  scanned_through: { block_number: 1058647120 }
  timestamp: 1785736840211
}
```

## V3 market-streaming service

`MarketStreaming` exposes fourteen typed subscriptions:

| Method                   | Opening behavior                                                    |
| ------------------------ | ------------------------------------------------------------------- |
| `StreamL2Book`           | Current full L2 book, then coalesced full snapshots                 |
| `StreamBbo`              | Current top of book per requested coin, then changes                |
| `StreamL2BookDiff`       | Full-book snapshot per coin, then ordered level diffs               |
| `StreamL4Book`           | Full L4 snapshot for one coin, then native JSON diffs               |
| `StreamL4OrderUpdates`   | Typed snapshot frame, then typed order diffs                        |
| `StreamTpslUpdates`      | TP/SL snapshot frame, then lifecycle diffs                          |
| `StreamTrades`           | Live-only normalized trades                                         |
| `StreamAllFills`         | Live-only fills across the requested scope                          |
| `StreamUserFills`        | Live-only fills for one user                                        |
| `StreamBuilderFills`     | Live-only builder-attributed fills                                  |
| `StreamLiquidationFills` | Live-only liquidation fills                                         |
| `StreamCandle`           | Current tracked bucket when available, otherwise the next execution |
| `StreamAllMids`          | Current full perp-mid map, then changed maps                        |
| `StreamActiveAssetCtx`   | Current context for one perp, then changes                          |

These are live subscriptions without historical backfill. One RPC represents one subscription; cancel its context to unsubscribe. Most stateful views open with current state, while trades and all fills-family streams are live-only.

Snapshot-derived views (`StreamL2Book`, `StreamBbo`, `StreamCandle`, `StreamAllMids`, and `StreamActiveAssetCtx`) recover from subscriber lag in-band because a later frame supersedes dropped state. Incremental streams terminate with `ABORTED` on frame loss; reconnect and rebuild from their opening snapshot where provided. `StreamL2BookDiff` chains `seq` and `prev_seq` per coin. Typed L4, TP/SL, and fills-family streams expose a per-subscription `sequence`; a gap means loss.

Market streams carry no heartbeat frames, and an idle subscription can be healthy. `INVALID_ARGUMENT` identifies malformed requests, `FAILED_PRECONDITION` an unavailable feature, `UNAVAILABLE` a view that is not yet ready or whose latest upstream data is stale, `ABORTED` lost frames or reset state, and `DEADLINE_EXCEEDED` a consumer that did not drain promptly.

Prices and sizes are decimal strings. Times are Unix milliseconds. Coin identifiers use native, case-sensitive names such as `BTC`, `@1`, and `#2`. User addresses match case-insensitively. Frame-level `time` is block time, while per-order `timestamp` is placement time. `StreamAllMids` and `StreamActiveAssetCtx` have no `block_number`; their `time` identifies when the endpoint made the update available, not a block or upstream timestamp.

## V2 compatibility

V2 retains the fourteen established raw methods and their feed-specific response messages. Its request cursor fields are `timestamp_ms` and `block_height`, and its pages remain at the same flat canonical URLs. V2 has no `ListFeeds`, shared `Record`, mempool methods, or V3 server-side raw filtering. Each overlapping method page keeps the V2 shape and adds its V3 equivalent.

## Client guidance

- Generate stubs from the exact proto version you call.
- Attach `x-api-key` metadata on every RPC and use TLS.
- Set deadlines on unary calls, especially unpositioned V3 raw calls that wait for the next record.
- Persist only present V3 cursors and replay inclusively after reconnecting; deduplicate the last committed cursor.
- Opt filtered raw streams in to [progress frames](#progress-frames) when they pass through proxies with idle timeouts, and persist `scanned_through` as a cursor.
- Drain streams continuously and reconnect with bounded exponential backoff for retryable statuses.
- Seed order-book reconstruction from a snapshot or another known state, then apply ordered diffs. Raw diffs alone are insufficient.

Complete client examples are available in the [Dwellir gRPC examples repository](https://github.com/dwellir-public/gRPC-code-examples). For help with deployment capabilities, contact <support@dwellir.com>.

---

## Historical Data - Hyperliquid Market Archives

# Historical Data - Hyperliquid Market Archives

Dwellir preserves Hyperliquid node data in its source record formats and offers processed datasets for backtesting, research, and analysis. This page is the single inventory for S3 Bucket contents, formats, access, pricing, and product selection.

For sample design, manifests, timestamp semantics, TWAP joins, liquidations, account-state replay, and commercial use, see [archive research and validation](https://www.dwellir.com/docs/hyperliquid/research).

## S3 bucket coverage

| Prefix                                                                                     | From         | To           | Object shape                  | Compressed size |  Files | Average/month | Files/month |
| ------------------------------------------------------------------------------------------ | ------------ | ------------ | ----------------------------- | --------------: | -----: | ------------: | ----------: |
| [`replica_cmds`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks)                         | `2025-01-25` | today        | LZ4-compressed native records |        80.65 TB | 68,993 |       4.99 TB |       3,766 |
| [`node_trades`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                           | `2025-03-22` | `2025-05-25` | `.lz4`                        |        15.13 GB |  1,541 |       6.73 GB |         720 |
| [`node_fills`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                            | `2025-05-25` | `2025-07-27` | `.lz4`                        |        31.81 GB |  1,507 |      13.49 GB |         720 |
| [`node_fills_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                   | `2025-07-27` | today        | `hourly .lz4`                 |       294.58 GB | 10,288 |      25.98 GB |         736 |
| [`node_order_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/order-statuses) | `2026-01-22` | today        | `hourly .lz4`                 |        18.56 TB |  6,000 |       2.19 TB |         736 |
| [`node_raw_book_diffs_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/book-diffs)     | `2026-01-22` | today        | `hourly .lz4`                 |         3.50 TB |  6,000 |     458.80 GB |         736 |
| [`misc_events_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/misc-events)            | `2026-06-29` | today        | `hourly .lz4`                 |        25.76 GB |  2,161 |       8.54 GB |         744 |
| [`node_twap_statuses_by_block`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/twap-statuses)   | `2026-07-01` | today        | `hourly .lz4`                 |         2.90 GB |  2,160 |       1.00 GB |         744 |
| [`orderbook_snapshots`](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots)             | `2026-04-14` | today        | `<height>.json.lz4`           |       283.03 GB | 19,115 |      56.01 GB |       3,765 |
| [`periodic_abci_states`](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/abci-states)            | `2026-04-14` | today        | `<height>.rmp.lz4`            |        15.79 TB | 20,718 |       2.90 TB |       3,766 |

## Compressed size and file count

The coverage table shows the compressed download size and file count for each available prefix. You can use these totals before buying archive access.

Sizes use decimal units: 1 GB is 1 billion bytes, and 1 TB is 1 trillion bytes. Decompressed files need additional storage.

Monthly averages use the last three calendar months with files on every date. Shorter histories use fewer months.

For a selected range, estimate volume as `days / 30.5 × monthly average`. Trading activity changes file sizes, so the result is approximate.

File count is the number of compressed files, not the number of blocks, events, or orders. File dates do not establish that every source record is present.

## Archive formats

Native JSON and JSONL payloads are LZ4-compressed. Decompress `.lz4` objects before parsing the record shape for their prefix. Generated order-book snapshots use `<height>.json.lz4`, while periodic ABCI state uses `<height>.rmp.lz4`. The latter contains RMP-encoded node state, not JSON.

Most current `*_by_block` feeds use an envelope with `local_time`, `block_time`, sequential `block_number`, and a feed-specific `events` array. The `replica_cmds` records contain `abci_block` and execution responses. Its `abci_block.round` is a consensus round, can skip, and must not be treated as the sequential block number.

The fills history spans 3 stored prefix generations:

| Prefix                | Native shape                                           | Useful fields                                                       |
| --------------------- | ------------------------------------------------------ | ------------------------------------------------------------------- |
| `node_trades`         | Trade record with a `side_info` array for participants | `coin`, `side`, `time`, `px`, `sz`, `hash`, participant order IDs   |
| `node_fills`          | User address paired with a fill object                 | Price, size, direction, PnL, fee, order ID, trade ID, and fee token |
| `node_fills_by_block` | Block envelope containing per-account fill events      | Current fill fields plus block context and builder attribution      |

Observed objects for these generations overlap, so their bounds are not mutually exclusive schema cutover dates. Select the parser from the object prefix and record shape. For processed analysis, [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data) converts `node_fills_by_block` records into CSV or Parquet. For query access, use the [Hyperliquid Index fills API](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills).

Current field-level references are available for [blocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks), [fills](https://www.dwellir.com/docs/hyperliquid/stream_fills), [order statuses](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses), [raw book diffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs), [misc events](https://www.dwellir.com/docs/hyperliquid/stream_misc_events), and [TWAP statuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses).

Each [data catalog](https://www.dwellir.com/docs/hyperliquid/data-catalog) page also has an "Observed fields" tree. It lists every field seen in one real archive object for that prefix, including the `periodic_abci_states` key structure.

Order-book reconstruction requires a known state seed, such as an `orderbook_snapshots` object generated from periodic ABCI state, followed by ordered `node_raw_book_diffs_by_block` records. Raw diffs alone cannot establish the starting book.

## Choosing a historical product

| If you need                                                                                        | Use                                                                  |
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| Native blocks, fills, order events, book diffs, misc events, TWAP events, snapshots, or ABCI state | S3 bucket coverage above                                             |
| Full-resolution trades in a columnar or spreadsheet-friendly format                                | [Tick data](https://www.dwellir.com/docs/hyperliquid/tick-data)                             |
| Wallet, builder, market, or historical-order queries over an API                                   | [Hyperliquid Index fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills) |
| 1s, 1m, or 5m price bars and exports                                                               | [OHLCV data](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data)         |
| Live L2/L4 books, BBO, and trades                                                                  | [Order Book WebSocket](https://www.dwellir.com/docs/hyperliquid/order-book-server)          |
| Live raw feeds or derived V3 market streams                                                        | [gRPC streaming](https://www.dwellir.com/docs/hyperliquid/grpc)                             |

To discover symbols before requesting data, use the [Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint). Perpetual names come from `meta`; spot names come from `spotMeta`.

## Real-Time Data

For live market data, see:

- [Order Book Server](https://www.dwellir.com/docs/hyperliquid/order-book-server) - Real-time L2/L4 order books and trades
- [gRPC Streaming](https://www.dwellir.com/docs/hyperliquid/grpc) - StreamBlocks, StreamFills, and more

## Pricing

| Product                                                                                                                                      | How it is priced                                                                                                                                                                                                                                                       |
| -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Hyperliquid Index APIs ([OHLCV candles](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data), [fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)) | Included in Dwellir API plans, from $49/month on Developer. 1 response = 1 API credit. Candle range pages bill 1 credit per returned candle.                                                                                                                           |
| [OHLCV full-history exports](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/full-history-exports)                                            | Export credits bought on the dashboard OHLCV Data tab. 1 credit = 1 export of one market at one interval in one format, whatever the file size. Per-credit prices get lower as you buy more, and an unlimited tier is available. Re-downloads within 30 days are free. |
| S3 Bucket archive prefixes and [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data)                                                                      | Quoted per dataset, as a monthly feed or a full-history purchase. Email <support@dwellir.com> with the prefix, date range, and format.                                                                                                                                 |

API plan prices, included responses, and rate limits are on the [pricing page](https://www.dwellir.com/pricing). Current export credit prices are shown on the [OHLCV Data tab](https://dashboard.dwellir.com/hyperliquid?tab=ohlcv).

## Access

For OHLCV data: **[sign up](https://dashboard.dwellir.com/register)** at the dashboard and visit the **[OHLCV Data tab](https://dashboard.dwellir.com/hyperliquid?tab=ohlcv)** to buy export credits and generate CSV or Parquet files for any market at 1s, 1m, or 5m intervals.

For S3 Bucket archival data, tick data, and other historical products:

**Email**: <support@dwellir.com>

Include in your request:

- Prefix or data product needed
- Date range
- Preferred format
- Use case description

Use the [coverage table](#s3-bucket-coverage) and [date-range estimator](#compressed-size-and-file-count) to plan downloads before purchase.

### One-off windows and filtered exports

S3 archive delivery is scoped by prefix and date. Each file covers every market, so you filter markets and exact time bounds after download. A short window still delivers the full files that contain it.

An export filtered to specific markets, decoded fields, or derived values is custom work. Dwellir quotes it separately by email. Prices and delivery times for custom work are not published.

For a custom request, also include:

- Markets
- UTC start and end, with an inclusive start and exclusive end
- Each field you need, with the source timestamp and block position you expect
- Whether you need a completeness or gap report

Check first whether a prefix stores the field. Mark and oracle prices, for example, are [not stored as their own records](https://www.dwellir.com/docs/hyperliquid/research#can-i-get-every-historical-mark-price-update).

After payment, Dwellir issues a read-only S3 key limited to the purchased prefixes and dates.

## Frequently asked questions

### How large are the archive files, and how many files will I receive?

The [coverage table](#s3-bucket-coverage) lists compressed size and file count per prefix. Use the [date-range estimator](#compressed-size-and-file-count) for a shorter selection. Download volume varies with trading activity.

### Which Hyperliquid historical data should I use for backtesting?

It depends on what your strategy trades on. Bar-based strategies can use [OHLCV candles](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data) at `1s`, `1m`, or `5m`. Execution backtests need fill-level [tick data](https://www.dwellir.com/docs/hyperliquid/tick-data) or the `node_fills_by_block` prefix. Order-level replay needs `orderbook_snapshots` plus `node_raw_book_diffs_by_block`. Their overlapping archive coverage starts on `2026-04-14`.

### How far back does Hyperliquid historical data go?

`replica_cmds` starts on `2025-01-25`. Fills start on `2025-03-22` in the `node_trades` prefix, and `node_fills_by_block` plus OHLCV candles start on `2025-07-27`. The full per-prefix table is in [S3 bucket coverage](#s3-bucket-coverage).

### Can Dwellir export every mark-price update for a time window?

No prefix stores mark prices as their own records. Applied values come from replaying `replica_cmds` from a periodic ABCI state checkpoint. See [historical mark prices](https://www.dwellir.com/docs/hyperliquid/research#can-i-get-every-historical-mark-price-update) for the inputs and their limits, and [one-off windows](#one-off-windows-and-filtered-exports) to request a quote.

### How much does Hyperliquid historical data cost?

API plans start at $49/month, and 1 response = 1 API credit. OHLCV exports cost 1 export credit per market, interval, and format. S3 Bucket archive data and tick data are quoted per dataset. See [Pricing](#pricing).

---

## hl_getBatchBlocks - Get Batch Fill Blocks

# hl_getBatchBlocks - Get Batch Fill Blocks

Return fill blocks in a `[from, to]` range for a given stream.

## Endpoint

```text
POST https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore
```

Use this method for block retrieval. `hl_getBlockByNumber` is not implemented
on this endpoint; to fetch a single block, set `from` and `to` to the same
recent block number.

## When to Use This Method

`hl_getBatchBlocks` is essential for:

- **Backfilling** — Retrieve historical fill data in bulk
- **Batch Processing** — Process trade events in ordered block ranges
- **Analytics Pipelines** — Feed fill data into downstream systems
- **Reconciliation** — Verify trade execution across block ranges

## Request Parameters

- `stream` (`string, required`): parameter: Data stream. Must be `"trades"`
- `from` (`integer, required`): parameter: First block number (inclusive, must be > 0 and within retention)
- `to` (`integer, required`): parameter: Last block number (inclusive, must be >= from and within retention)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "hl_getBatchBlocks",
  "params": { "stream": "trades", "from": 907626062, "to": 907626064 },
  "id": 1
}
```

## Response Fields

- `blocks` (`array, required`): Array of block objects in the requested range

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": {
    "blocks": [
      {
        "local_time": "2026-02-27T09:58:16.738110784",
        "block_time": "2026-02-27T09:58:16.410825222",
        "block_number": 907626062,
        "events": [
          [
            "0x9f9a72b449783e6a7e9afca2efa49a6b77793555",
            {
              "coin": "ETH",
              "px": "2010.8",
              "sz": "0.02",
              "side": "B",
              "time": 1772186296410,
              "startPosition": "0.0543",
              "dir": "Open Long",
              "closedPnl": "0.0",
              "hash": "0x92bca362a1e7aad59436043619464e0203a000483ceac9a736854eb560eb84c0",
              "oid": 331832891533,
              "crossed": false,
              "fee": "0.005791",
              "tid": 379919209298471,
              "feeToken": "USDC",
              "twapId": null
            }
          ],
          [
            "0xf8ae6942b61c6cd0333d174244f2be138626a89e",
            {
              "coin": "ETH",
              "px": "2010.8",
              "sz": "0.02",
              "side": "A",
              "time": 1772186296410,
              "startPosition": "0.0",
              "dir": "Open Short",
              "closedPnl": "0.0",
              "hash": "0x92bca362a1e7aad59436043619464e0203a000483ceac9a736854eb560eb84c0",
              "oid": 331834694017,
              "crossed": true,
              "fee": "0.017373",
              "tid": 379919209298471,
              "feeToken": "USDC",
              "twapId": null
            }
          ]
        ]
      },
      {
        "local_time": "2026-02-27T09:58:16.935172042",
        "block_time": "2026-02-27T09:58:16.511724597",
        "block_number": 907626064,
        "events": []
      }
    ]
  },
  "id": 1
}
```

## Error Responses

### Requested range not available yet

- Code: `-32002`
- Description: The requested block range is newer than the batch index currently serves.

### Requested range pruned

- Code: `-32003`
- Description: The requested block range is older than the retained indexed data.

## Billing

`hl_getBatchBlocks` is billed by the number of block objects returned in `result.blocks`, not as one response per HTTP request.
A response with `100` blocks counts as `100` responses/API credits.

JSON-RPC error responses are not charged.

## Curl Example

```bash
ENDPOINT='https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/YOUR_API_KEY/hypercore'

LATEST_BLOCK=$(curl -s -X POST "$ENDPOINT" \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "hl_getLatestBlockNumber",
    "params": { "stream": "trades" },
    "id": 1
  }' | jq -r '.result')

FROM_BLOCK=$((LATEST_BLOCK - 100))

curl -X POST "$ENDPOINT" \
  -H 'Content-Type: application/json' \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"hl_getBatchBlocks\",
    \"params\": { \"stream\": \"trades\", \"from\": $FROM_BLOCK, \"to\": $FROM_BLOCK },
    \"id\": 2
  }"
```

## Common Use Cases

### 1. Sequential Backfill

Fetch all blocks from a known starting point to the latest:

```javascript
async function backfill(startBlock) {
  const response = await fetch(ENDPOINT, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'hl_getLatestBlockNumber',
      params: { stream: 'trades' },
      id: 1
    })
  });
  const { result: latestBlock } = await response.json();

  let current = startBlock;
  while (current <= latestBlock) {
    const to = Math.min(current + 99, latestBlock);
    const blocks = await getBatchBlocks(current, to);
    console.log(`Fetched blocks ${current}–${to}: ${blocks.length} blocks`);

    for (const block of blocks) {
      // Process each block
    }

    current = to + 1;
  }
}
```

### 2. Event Counting

Count fill events across a block range:

```python
def count_events(from_block: int, to_block: int) -> dict:
    blocks = get_batch_blocks(from_block, to_block)

    total_events = 0
    for block in blocks:
        total_events += len(block['events'])

    return {
        'block_range': f"{from_block}–{to_block}",
        'blocks_returned': len(blocks),
        'total_events': total_events
    }
```

## Best Practices

1. **Respect the batch limit** — Keep ranges at or below 100 blocks per request
2. **Use sequential fetching** — Combine with `hl_getLatestBlockNumber` to walk forward
3. **Stay within retention** — Older ranges can return `-32003` with `requested range pruned`
4. **Handle sparse ranges** — Some blocks in a range may have no events
5. **Implement retries** — Use exponential backoff for transient errors

## Related Methods

- [**hl\_getLatestBlockNumber**](https://www.dwellir.com/docs/hyperliquid/hl_getLatestBlockNumber) — Get the latest available block number

***

*Query HyperCore fill data with Dwellir's JSON-RPC API. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## hl_getLatestBlockNumber - Get Latest Block Number

# hl_getLatestBlockNumber - Get Latest Block Number

Return the highest block number currently available for a given stream.

## Endpoint

```text
POST https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore
```

Use this JSON-RPC endpoint for trade-fill block cursors. It is not the
HyperCore Info endpoint, which uses `{"type": "..."}` request bodies at
`https://api-hyperliquid-mainnet-info.n.dwellir.com/<API-KEY>/info`.

## When to Use This Method

`hl_getLatestBlockNumber` is essential for:

- **Synchronization** — Determine the current head before fetching batch blocks
- **Polling** — Check for new blocks at regular intervals
- **Catch-up Logic** — Calculate how far behind your consumer is
- **Health Monitoring** — Verify the data pipeline is advancing

## Request Parameters

- `stream` (`string, required`): parameter: Data stream. Must be `"trades"`

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "hl_getLatestBlockNumber",
  "params": { "stream": "trades" },
  "id": 1
}
```

## Response Fields

- `result` (`integer, required`): The highest block number available for the stream

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": 907628737,
  "id": 1
}
```

## Curl Example

```bash
curl -X POST 'https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/YOUR_API_KEY/hypercore' \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "hl_getLatestBlockNumber",
    "params": { "stream": "trades" },
    "id": 1
  }'
```

If you receive `{"code":-32601,"message":"method not found: hl_getBlockByNumber"}`,
the request body is using an unsupported method. Use `hl_getLatestBlockNumber`
for the current cursor, or `hl_getBatchBlocks` for one or more fill blocks.

## Common Use Cases

### 1. Poll for New Blocks

Check for new data at regular intervals:

```javascript
async function pollForNewBlocks(callback, intervalMs = 5000) {
  let lastSeen = await getLatestBlockNumber();
  console.log(`Starting poll from block ${lastSeen}`);

  setInterval(async () => {
    const latest = await getLatestBlockNumber();

    if (latest > lastSeen) {
      console.log(`New blocks: ${lastSeen + 1} to ${latest}`);
      callback(lastSeen + 1, latest);
      lastSeen = latest;
    }
  }, intervalMs);
}

// Usage
pollForNewBlocks((from, to) => {
  console.log(`Processing blocks ${from}–${to}`);
});
```

### 2. Calculate Consumer Lag

Monitor how far behind a consumer is:

```python
def check_lag(consumer_block: int) -> dict:
    latest = get_latest_block_number()
    lag = latest - consumer_block

    return {
        'consumer_block': consumer_block,
        'latest_block': latest,
        'lag_blocks': lag,
        'status': 'healthy' if lag < 100 else 'behind'
    }
```

## Best Practices

1. **Poll responsibly** — Don't poll more frequently than every few seconds
2. **Use as a cursor** — Combine with `hl_getBatchBlocks` for sequential data retrieval
3. **Monitor lag** — Track the difference between your consumer position and the latest block
4. **Handle stale data** — If the latest block number hasn't advanced, the upstream may be paused

## Related Methods

- [**hl\_getBatchBlocks**](https://www.dwellir.com/docs/hyperliquid/hl_getBatchBlocks) — Retrieve fill blocks in a range

***

*Query HyperCore fill data with Dwellir's JSON-RPC API. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## Hyperliquid Index

# Hyperliquid Index

The Hyperliquid Index is Dwellir's indexed market-data surface for HyperCore. Use it when you need queryable history or derived market data without parsing raw node archives yourself.

```text
https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY
```

The Index serves indexed history for fills, candles, and outcome markets. To see how these map to raw node feeds and live streams, start from [How Hyperliquid works](https://www.dwellir.com/docs/hyperliquid#how-hyperliquid-works).

## Available Data

| Product                                                                      | Transport                          | Use case                                                                             |
| ---------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------ |
| [OHLCV Data](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data)                 | REST, JSON-RPC, WebSocket, exports | Sparse candlesticks for all indexed Hyperliquid markets                              |
| [Historical Fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills)                | REST-style `/info`, JSON-RPC       | User, builder, global, and liquidation execution history                             |
| [HIP-4 Outcome Markets](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets) | REST-style `/info`, JSON-RPC       | Outcome metadata, registration events, settlement events, and outcome-specific fills |

## When to Use Hyperliquid Index

- Build charts and dashboards from normalized candle data.
- Retrieve historical fills for wallet analytics, builder attribution, and execution review.
- Track HIP-4 outcome market lifecycle events and outcome-side execution history.
- Query indexed historical data with a Dwellir API key.
- Use one public host for OHLCV and historical fill retrieval.

If you need raw live L1 payloads instead of indexed history, use the [L1 gRPC Streaming API](https://www.dwellir.com/docs/hyperliquid/grpc). If you need low-latency live order book updates, use the [Order Book WebSocket API](https://www.dwellir.com/docs/hyperliquid/order-book-server).

---

## Hyperliquid Historical Fills

# Hyperliquid Historical Fills

Historical fills expose indexed Hyperliquid executions from Dwellir's Hyperliquid Index. Use these endpoints for wallet execution history, builder attribution, global fill sampling, liquidation analysis, and TWAP slice execution history.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

For `/info`, set `type` to the method name. For JSON-RPC, set `method` to the same value and pass the request fields under `params`.

## Billing

Fill history responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `2,000` fills counts as `2,000` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Methods

| Method                                                                                                | Use case                                                                                            |
| ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| [`userFills`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-fills)                                   | Latest fills for one user address                                                                   |
| [`userFillsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-fills-by-time)                     | User fills inside a bounded time window                                                             |
| [`builderFills`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/builder-fills)                             | Latest fills attributed to one builder address                                                      |
| [`builderFillsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/builder-fills-by-time)               | Builder-attributed fills inside a bounded time window                                               |
| [`allFills`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/all-fills)                                     | Latest fills across indexed users and markets                                                       |
| [`allFillsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/all-fills-by-time)                       | Global fills inside a bounded time window; `endTime` is required and the window is capped at 1 hour |
| [`userTwapSliceFills`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-slice-fills)               | Latest executed TWAP slice fills for one user                                                       |
| [`userTwapSliceFillsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-slice-fills-by-time) | User TWAP slice fills inside a bounded time window                                                  |
| [`userTwapSummaries`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-summaries)                  | Recent execution-derived TWAP summaries for one user                                                |
| [`userTwapSummariesByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-summaries-by-time)    | Windowed execution-derived TWAP summaries for one user                                              |
| [`liquidationFills`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/liquidation-fills)                     | Latest fills with liquidation metadata                                                              |
| [`liquidationFillsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/liquidation-fills-by-time)       | Liquidation fills inside a bounded time window                                                      |
| [`builderLiquidations`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/builder-liquidations)               | Latest liquidation fills attributed to one builder address                                          |
| [`builderLiquidationsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/builder-liquidations-by-time) | Builder-attributed liquidation fills inside a bounded time window                                   |
| [`historicalOrders`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/historical-orders)                     | Latest order status updates for one user                                                            |
| [`historicalOrdersByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/historical-orders-by-time)       | User order status updates inside a bounded time window                                              |

## Server-side Market Filtering

All fill, liquidation, TWAP, builder-fill, and historical-order methods in this section accept an optional `coin` parameter for exact server-side market filtering, for example `"coin": "BTC"`. When supplied, only rows whose `coin` field matches that market symbol are returned.

## Shared Fill Fields

Most methods return an array of fill objects:

| Field           | Description                                                                                            |
| --------------- | ------------------------------------------------------------------------------------------------------ |
| `coin`          | Hyperliquid market symbol                                                                              |
| `px`            | Execution price as a decimal string                                                                    |
| `sz`            | Fill size as a decimal string                                                                          |
| `side`          | `B` for bid/buy side, `A` for ask/sell side                                                            |
| `time`          | Fill timestamp in Unix milliseconds                                                                    |
| `startPosition` | User position before the fill, when available                                                          |
| `dir`           | Position direction, for example `Open Long` or `Close Short`                                           |
| `closedPnl`     | Realized PnL from the fill as a decimal string                                                         |
| `hash`          | Hyperliquid transaction hash                                                                           |
| `oid`           | Hyperliquid order ID                                                                                   |
| `crossed`       | Whether the order crossed the spread                                                                   |
| `fee`           | User fee amount                                                                                        |
| `tid`           | Trade ID, when available                                                                               |
| `feeToken`      | Token used for fees, usually `USDC`                                                                    |
| `builder`       | Builder address, when the fill was builder-routed                                                      |
| `builderFee`    | Builder fee amount, when available                                                                     |
| `twapId`        | TWAP order ID, when available                                                                          |
| `cloid`         | Client order ID, when available                                                                        |
| `txIndex`       | Block-local fill event index from `node_fills_by_block`; use with `time` for stable by-time pagination |

Global, builder, and liquidation responses also include `user` so you can attribute each fill to the account that produced it.

To find the wallet behind a single order ID or transaction hash, see [How to find the wallet behind a Hyperliquid order](https://www.dwellir.com/guides/hyperliquid-find-order-wallet).

## TWAP Summary Fields

`userTwapSummaries` and `userTwapSummariesByTime` return execution-derived TWAP summaries instead of raw fill rows:

| Field           | Description                                                                      |
| --------------- | -------------------------------------------------------------------------------- |
| `user`          | User address                                                                     |
| `twapId`        | TWAP order ID                                                                    |
| `coin`          | Hyperliquid market symbol                                                        |
| `side`          | `B` for bid/buy side, `A` for ask/sell side                                      |
| `avgPx`         | Size-weighted average execution price for indexed slice fills                    |
| `sz`            | Total executed size across indexed slice fills                                   |
| `fee`           | Total user fee across indexed slice fills                                        |
| `closedPnl`     | Total realized PnL across indexed slice fills                                    |
| `nSlices`       | Number of slice fill rows included in the summary                                |
| `firstFillTime` | Earliest slice fill timestamp in Unix milliseconds                               |
| `lastFillTime`  | Latest slice fill timestamp in Unix milliseconds                                 |
| `txIndex`       | Block-local fill event index for the latest slice in the summary, when available |

TWAP summaries are derived from observed executions in the index. They do not expose the full parent TWAP order intent or configuration.

## Historical Order Fields

`historicalOrders` and `historicalOrdersByTime` return order status updates instead of fill rows:

| Field             | Description                                                                       |
| ----------------- | --------------------------------------------------------------------------------- |
| `builder`         | Builder address, when the order was builder-routed                                |
| `txIndex`         | Block-local order status event index, when available                              |
| `status`          | Current order status for this update, for example `filled`, `open`, or `canceled` |
| `statusTimestamp` | Status update timestamp in Unix milliseconds                                      |
| `order`           | Nested order object                                                               |
| `order.coin`      | Hyperliquid market symbol                                                         |
| `order.side`      | `B` for bid/buy side, `A` for ask/sell side                                       |
| `order.limitPx`   | Limit price as a decimal string                                                   |
| `order.sz`        | Order size as a decimal string                                                    |
| `order.oid`       | Hyperliquid order ID                                                              |
| `order.timestamp` | Original order timestamp in Unix milliseconds                                     |
| `order.orderType` | Order type, such as `Limit`                                                       |
| `order.origSz`    | Original order size as a decimal string                                           |
| `order.tif`       | Time-in-force value, when available                                               |
| `order.cloid`     | Client order ID, when available                                                   |

## Pagination and Limits

`limit` defaults to the service default and is capped at `2000` for fill-row methods. TWAP summary methods are capped at `500`.

By-time methods accept `cursor` in `time_txIndex` format. When `cursor` is supplied, `startTime` is skipped and the next page resumes after that `(time, txIndex)` pair. `txIndex` is the fill's block-local position in the `node_fills_by_block` event array, not a `replica_cmds`-compatible action index. Fill methods return a fill array, not a cursor. Build `cursor` from the last fill's `time` and `txIndex`.

For `allFillsByTime`, keep the same `endTime` until that hour is exhausted. The 1-hour cap is measured from the cursor time, so do not advance `endTime` until the current window is done.

For `userTwapSummariesByTime`, the cursor uses the grouped summary's `lastFillTime_txIndex`. Keep the same `startTime` and `endTime` across cursor pages so the summary window stays stable.

For `historicalOrdersByTime`, the cursor uses `statusTimestamp_txIndex_oid`. The `oid` suffix prevents rows with the same status timestamp and `txIndex` from being skipped across pages.

---

## allFills - Global Fill History

# allFills - Global Fill History

Use `allFills` when you need a recent global sample of indexed Hyperliquid executions across users and markets. Every row includes `user`.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`allFills` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `2,000` fills counts as `2,000` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be allFills for /info REST requests. Omit this field for JSON-RPC.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "allFills",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "allFills",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "allFills",
  "params": {
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## allFillsByTime - Global Fill History by Time

# allFillsByTime - Global Fill History by Time

Use `allFillsByTime` to scan indexed fills across users and markets inside a bounded time window. `endTime` is required on every request, and the window may span at most 1 hour.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Time window limits

`allFillsByTime` is the only fills method that is not scoped to one user or one builder, so the requested time window is the only bound on the scan. Four rules apply to this method:

- `endTime` is required. An open-ended request is rejected, on the first request and on every cursor page.
- `endTime` must be greater than `startTime`, or greater than the cursor time when you page with `cursor`.
- The window must be at most **1 hour**. On a cursor page the span is measured from the cursor time, not from the original `startTime`.
- `endTime` must not be in the future, beyond a 5-minute clock-skew tolerance. This also catches the common wrong-unit mistake: `endTime` is epoch **milliseconds**, not microseconds or nanoseconds.

`/info` returns a fill array. It does not return a `cursor`. Build the next
`cursor` from the last fill as `time_txIndex`, for example `1753606210273_1`.
Keep the same `endTime` and send that cursor until a page is shorter than
`limit`. Then set `startTime` to that `endTime` and pick a new `endTime` at
most 1 hour later. A busy hour needs many pages: one BTC hour filled the
2,000-row cap in about 2 minutes of fill time. If you move `endTime` while
the cursor is still more than 1 hour behind it, the request is rejected.

A request that breaks any of these rules is rejected before it reaches the index, so it is not billed. `POST /info` returns HTTP `400` and `POST /jsonrpc` returns JSON-RPC error `-32602` (invalid params). Both responses name the parameter and carry a copy-pasteable example.

REST `/info` error body:

```json
{
  "error": "invalid request: endTime is required for allFillsByTime and must be greater than startTime (or greater than the cursor time when paging); pass it as epoch milliseconds, at most 1h after the start, for example {\"type\":\"allFillsByTime\",\"coin\":\"BTC\",\"startTime\":1753606200000,\"endTime\":1753606300000,\"limit\":100}"
}
```

JSON-RPC error body:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request: the allFillsByTime window 24h exceeds the maximum 1h; the whole window is scanned before the limit applies, so page through it in smaller windows (example: {\"type\":\"allFillsByTime\",\"coin\":\"BTC\",\"startTime\":1753606200000,\"endTime\":1753606300000,\"limit\":100})"
  }
}
```

The `coin` filter does not shrink the window you may request. Rows are ordered by time on this method, so `coin` narrows the returned results, not the range that is read. Every other `*ByTime` fill method keeps `endTime` optional, because those are scoped to a user or a builder.

## Billing

`allFillsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `2,000` fills counts as `2,000` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the fill's block-local position in the `node_fills_by_block` event array. It is exposed as a stable fill pagination key, not as a `replica_cmds`-compatible action index.

## Request Parameters

- `type` (`string, required`): Must be allFillsByTime for /info REST requests. Omit this field for JSON-RPC.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, required`): Exclusive Unix timestamp in milliseconds. Required on the first request and on every cursor page. Must be greater than startTime, or greater than the cursor time when paging, and at most 1 hour after it. An endTime in the future is rejected beyond a 5-minute clock-skew tolerance.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. The response is a fill array with no cursor field, so build this value from the last fill's time and txIndex. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "allFillsByTime",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for stable by-time pagination.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1
  }
]
```

## Error Responses

### Missing endTime (REST)

- Code: `400`
- Description: REST /info rejects a request without endTime before it reaches the index, so it is not billed.

```json
{
  "error": "invalid request: endTime is required for allFillsByTime and must be greater than startTime (or greater than the cursor time when paging); pass it as epoch milliseconds, at most 1h after the start, for example {\"type\":\"allFillsByTime\",\"coin\":\"BTC\",\"startTime\":1753606200000,\"endTime\":1753606300000,\"limit\":100}"
}
```

### Window over 1 hour (JSON-RPC)

- Code: `-32602`
- Description: JSON-RPC returns invalid params when the window exceeds 1 hour, measured from startTime or from the cursor time.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request: the allFillsByTime window 24h exceeds the maximum 1h; the whole window is scanned before the limit applies, so page through it in smaller windows (example: {\"type\":\"allFillsByTime\",\"coin\":\"BTC\",\"startTime\":1753606200000,\"endTime\":1753606300000,\"limit\":100})"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "allFillsByTime",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

Cursor page of the same window. `endTime` stays put. `cursor` is the last fill's `time` and `txIndex`:

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "allFillsByTime",
  "coin": "BTC",
  "cursor": "1753606210273_1",
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "allFillsByTime",
  "params": {
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors. The array has no cursor field. Build the next `cursor` from the last fill's `time` and `txIndex`.

---

## builderFills - Builder Fill History

# builderFills - Builder Fill History

Use `builderFills` to retrieve recent fills routed through a builder address. Results include `user` and `builderFee` when available.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`builderFills` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be builderFills for /info REST requests. Omit this field for JSON-RPC.
- `builder` (`string, required`): 0x-prefixed builder address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderFills",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderFills",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "builderFills",
  "params": {
    "builder": "0x2222222222222222222222222222222222222222",
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## builderFillsByTime - Builder Fill History by Time

# builderFillsByTime - Builder Fill History by Time

Use `builderFillsByTime` to retrieve builder-attributed fills inside a bounded time window.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`builderFillsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the fill's block-local position in the `node_fills_by_block` event array. It is exposed as a stable fill pagination key, not as a `replica_cmds`-compatible action index.

## Request Parameters

- `type` (`string, required`): Must be builderFillsByTime for /info REST requests. Omit this field for JSON-RPC.
- `builder` (`string, required`): 0x-prefixed builder address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderFillsByTime",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for stable by-time pagination.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderFillsByTime",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "builderFillsByTime",
  "params": {
    "builder": "0x2222222222222222222222222222222222222222",
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## builderLiquidations - Builder Liquidation Fills

# builderLiquidations - Builder Liquidation Fills

Use `builderLiquidations` to retrieve recent liquidation fills routed through a builder address. Results include liquidation metadata and the user account that produced each fill.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`builderLiquidations` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be builderLiquidations for /info REST requests. Omit this field for JSON-RPC.
- `builder` (`string, required`): 0x-prefixed builder address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderLiquidations",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.
- `liquidation` (`object, required`): Liquidation metadata.
- `liquidation.liquidatedUser` (`string, required`): User account liquidated by the fill.
- `liquidation.markPx` (`string, required`): Mark price at liquidation.
- `liquidation.method` (`string, required`): Liquidation method, such as backstop.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1,
    "liquidation": {
      "liquidatedUser": "0x3333333333333333333333333333333333333333",
      "markPx": "118000",
      "method": "backstop"
    }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderLiquidations",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "builderLiquidations",
  "params": {
    "builder": "0x2222222222222222222222222222222222222222",
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## builderLiquidationsByTime - Builder Liquidation Fills by Time

# builderLiquidationsByTime - Builder Liquidation Fills by Time

Use `builderLiquidationsByTime` to retrieve builder-attributed liquidation fills inside a bounded time window. Results are ordered by ascending fill time.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`builderLiquidationsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the fill's block-local position in the `node_fills_by_block` event array. It is exposed as a stable fill pagination key, not as a `replica_cmds`-compatible action index.

## Request Parameters

- `type` (`string, required`): Must be builderLiquidationsByTime for /info REST requests. Omit this field for JSON-RPC.
- `builder` (`string, required`): 0x-prefixed builder address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderLiquidationsByTime",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for stable by-time pagination.
- `liquidation` (`object, required`): Liquidation metadata.
- `liquidation.liquidatedUser` (`string, required`): User account liquidated by the fill.
- `liquidation.markPx` (`string, required`): Mark price at liquidation.
- `liquidation.method` (`string, required`): Liquidation method, such as backstop.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1,
    "liquidation": {
      "liquidatedUser": "0x3333333333333333333333333333333333333333",
      "markPx": "118000",
      "method": "backstop"
    }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "builderLiquidationsByTime",
  "builder": "0x2222222222222222222222222222222222222222",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "builderLiquidationsByTime",
  "params": {
    "builder": "0x2222222222222222222222222222222222222222",
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## historicalOrders - Historical Orders

# historicalOrders - Historical Orders

Use `historicalOrders` to retrieve recent order status updates for one Hyperliquid user address. Results are ordered newest first.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`historicalOrders` responses are billed by the number of order status objects returned, not as one response per HTTP request.
A response with `100` orders counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be historicalOrders for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "historicalOrders",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `orders` (`array, required`): Array of order status objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per order object returned.
- `builder` (`string, optional`): Builder address, when present.
- `txIndex` (`number, optional`): Block-local order status event index, when available.
- `status` (`string, required`): Order status for this update.
- `statusTimestamp` (`number, required`): Order status timestamp in Unix milliseconds.
- `order` (`object, required`): Nested order details.
- `order.coin` (`string, required`): Hyperliquid market symbol.
- `order.side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `order.limitPx` (`string, required`): Limit price as a decimal string.
- `order.sz` (`string, required`): Order size as a decimal string.
- `order.oid` (`number, required`): Hyperliquid order ID.
- `order.timestamp` (`number, required`): Original order timestamp in Unix milliseconds.
- `order.triggerCondition` (`string, optional`): Trigger condition, when present.
- `order.isTrigger` (`boolean, required`): Whether this is a trigger order.
- `order.triggerPx` (`string, optional`): Trigger price as a decimal string.
- `order.children` (`array, required`): Child orders associated with this order.
- `order.isPositionTpsl` (`boolean, required`): Whether this is a position take-profit or stop-loss order.
- `order.reduceOnly` (`boolean, required`): Whether the order is reduce-only.
- `order.orderType` (`string, required`): Order type, such as Limit.
- `order.origSz` (`string, optional`): Original order size as a decimal string.
- `order.tif` (`string, optional`): Time-in-force value, when present.
- `order.cloid` (`string, optional`): Client order ID, when present.

## Successful Response

```json
[
  {
    "builder": "0xb84168cf3be63c6b8dad05ff5d755e97432ff80b",
    "txIndex": 8,
    "status": "filled",
    "statusTimestamp": 1753606200000,
    "order": {
      "coin": "BTC",
      "side": "B",
      "limitPx": "45000",
      "sz": "0.5",
      "oid": 1234,
      "timestamp": 1753606100000,
      "triggerCondition": "N/A",
      "isTrigger": false,
      "triggerPx": "0",
      "children": [],
      "isPositionTpsl": false,
      "reduceOnly": true,
      "orderType": "Limit",
      "origSz": "0.5",
      "tif": "Gtc",
      "cloid": "0xabc"
    }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "historicalOrders",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "historicalOrders",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## historicalOrdersByTime - Historical Orders by Time

# historicalOrdersByTime - Historical Orders by Time

Use `historicalOrdersByTime` to retrieve order status updates for one Hyperliquid user inside a bounded time window. Results are ordered by ascending status timestamp.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`historicalOrdersByTime` responses are billed by the number of order status objects returned, not as one response per HTTP request.
A response with `100` orders counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

Use the last row from the previous page and pass `cursor` as `statusTimestamp_txIndex_oid`. The `oid` suffix prevents rows with the same status timestamp and `txIndex` from being skipped across pages.

## Request Parameters

- `type` (`string, required`): Must be historicalOrdersByTime for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in statusTimestamp_txIndex_oid format. Resumes after that order status update; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "historicalOrdersByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `orders` (`array, required`): Array of order status objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per order object returned.
- `builder` (`string, optional`): Builder address, when present.
- `txIndex` (`number, optional`): Block-local order status event index, when available.
- `status` (`string, required`): Order status for this update.
- `statusTimestamp` (`number, required`): Order status timestamp in Unix milliseconds.
- `order` (`object, required`): Nested order details.
- `order.coin` (`string, required`): Hyperliquid market symbol.
- `order.side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `order.limitPx` (`string, required`): Limit price as a decimal string.
- `order.sz` (`string, required`): Order size as a decimal string.
- `order.oid` (`number, required`): Hyperliquid order ID.
- `order.timestamp` (`number, required`): Original order timestamp in Unix milliseconds.
- `order.triggerCondition` (`string, optional`): Trigger condition, when present.
- `order.isTrigger` (`boolean, required`): Whether this is a trigger order.
- `order.triggerPx` (`string, optional`): Trigger price as a decimal string.
- `order.children` (`array, required`): Child orders associated with this order.
- `order.isPositionTpsl` (`boolean, required`): Whether this is a position take-profit or stop-loss order.
- `order.reduceOnly` (`boolean, required`): Whether the order is reduce-only.
- `order.orderType` (`string, required`): Order type, such as Limit.
- `order.origSz` (`string, optional`): Original order size as a decimal string.
- `order.tif` (`string, optional`): Time-in-force value, when present.
- `order.cloid` (`string, optional`): Client order ID, when present.

## Successful Response

```json
[
  {
    "builder": "0xb84168cf3be63c6b8dad05ff5d755e97432ff80b",
    "txIndex": 8,
    "status": "filled",
    "statusTimestamp": 1753606200000,
    "order": {
      "coin": "BTC",
      "side": "B",
      "limitPx": "45000",
      "sz": "0.5",
      "oid": 1234,
      "timestamp": 1753606100000,
      "triggerCondition": "N/A",
      "isTrigger": false,
      "triggerPx": "0",
      "children": [],
      "isPositionTpsl": false,
      "reduceOnly": true,
      "orderType": "Limit",
      "origSz": "0.5",
      "tif": "Gtc",
      "cloid": "0xabc"
    }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "historicalOrdersByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "historicalOrdersByTime",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## liquidationFills - Liquidation Fill History

# liquidationFills - Liquidation Fill History

Use `liquidationFills` to retrieve recent fills that include liquidation metadata. During backfill, this endpoint can return an empty array even while non-liquidation fill endpoints return rows.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`liquidationFills` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be liquidationFills for /info REST requests. Omit this field for JSON-RPC.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "liquidationFills",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.
- `liquidation` (`object, required`): Liquidation metadata.
- `liquidation.liquidatedUser` (`string, required`): User account liquidated by the fill.
- `liquidation.markPx` (`string, required`): Mark price at liquidation.
- `liquidation.method` (`string, required`): Liquidation method, such as backstop.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1,
    "liquidation": {
      "liquidatedUser": "0x3333333333333333333333333333333333333333",
      "markPx": "118000",
      "method": "backstop"
    }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "liquidationFills",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "liquidationFills",
  "params": {
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## liquidationFillsByTime - Liquidation Fill History by Time

# liquidationFillsByTime - Liquidation Fill History by Time

Use `liquidationFillsByTime` to retrieve liquidation fills inside a bounded time window. During backfill, this endpoint can return an empty array even when the method is available.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`liquidationFillsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the fill's block-local position in the `node_fills_by_block` event array. It is exposed as a stable fill pagination key, not as a `replica_cmds`-compatible action index.

## Request Parameters

- `type` (`string, required`): Must be liquidationFillsByTime for /info REST requests. Omit this field for JSON-RPC.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "liquidationFillsByTime",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for stable by-time pagination.
- `liquidation` (`object, required`): Liquidation metadata.
- `liquidation.liquidatedUser` (`string, required`): User account liquidated by the fill.
- `liquidation.markPx` (`string, required`): Mark price at liquidation.
- `liquidation.method` (`string, required`): Liquidation method, such as backstop.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "builderFee": "0.000531",
    "user": "0x1111111111111111111111111111111111111111",
    "txIndex": 1,
    "liquidation": {
      "liquidatedUser": "0x3333333333333333333333333333333333333333",
      "markPx": "118000",
      "method": "backstop"
    }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "liquidationFillsByTime",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "liquidationFillsByTime",
  "params": {
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## userFills - User Fill History

# userFills - User Fill History

Use `userFills` to retrieve the most recent indexed fills for one Hyperliquid user address. Results are ordered newest first.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`userFills` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be userFills for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userFills",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "txIndex": 1
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userFills",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "userFills",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## userFillsByTime - User Fill History by Time

# userFillsByTime - User Fill History by Time

Use `userFillsByTime` to retrieve indexed fills for one user inside a bounded time window. Results are ordered by ascending fill time.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`userFillsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the fill's block-local position in the `node_fills_by_block` event array. It is exposed as a stable fill pagination key, not as a `replica_cmds`-compatible action index.

## Request Parameters

- `type` (`string, required`): Must be userFillsByTime for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userFillsByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `builderFee` (`string, optional`): Builder fee amount, when present.
- `user` (`string, optional`): User address; present on global, builder, and liquidation methods.
- `twapId` (`number, optional`): TWAP order ID, when present.
- `cloid` (`string, optional`): Client order ID, when present.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for stable by-time pagination.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "118136",
    "sz": "0.00009",
    "side": "B",
    "time": 1753606210273,
    "startPosition": "-1.41864",
    "dir": "Close Short",
    "closedPnl": "-0.003753",
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.005316",
    "tid": 707098367501071,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "txIndex": 1
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userFillsByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "userFillsByTime",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## userTwapSliceFills - User TWAP Slice Fills

# userTwapSliceFills - User TWAP Slice Fills

Use `userTwapSliceFills` to retrieve the most recent indexed TWAP slice fills for one Hyperliquid user address. Results are ordered newest first and include only fills with a non-zero `twapId`.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`userTwapSliceFills` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be userTwapSliceFills for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSliceFills",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of TWAP slice fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `twapId` (`number, required`): TWAP order ID for the slice fill.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "100.5",
    "sz": "0.25",
    "side": "B",
    "time": 1753606200000,
    "startPosition": "1.0",
    "dir": "Open Long",
    "closedPnl": "0",
    "hash": "0xabc",
    "oid": 1234,
    "crossed": false,
    "fee": "0.01",
    "tid": 99,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "twapId": 1755601,
    "txIndex": 8
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSliceFills",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "userTwapSliceFills",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

Each fill row is a normal fill object with `twapId` populated. `txIndex` is the block-local fill event index from `node_fills_by_block`.

---

## userTwapSliceFillsByTime - User TWAP Slice Fills by Time

# userTwapSliceFillsByTime - User TWAP Slice Fills by Time

Use `userTwapSliceFillsByTime` to retrieve indexed TWAP slice fills for one user inside a bounded time window. Results are ordered by ascending fill time and include only fills with a non-zero `twapId`.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`userTwapSliceFillsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `100` fills counts as `100` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the fill's block-local position in the `node_fills_by_block` event array. It is exposed as a stable fill pagination key, not as a `replica_cmds`-compatible action index.

## Request Parameters

- `type` (`string, required`): Must be userTwapSliceFillsByTime for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSliceFillsByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of TWAP slice fill objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per fill object returned.
- `coin` (`string, required`): Hyperliquid market symbol.
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `startPosition` (`string, optional`): User position before the fill, when available.
- `dir` (`string, optional`): Position direction.
- `closedPnl` (`string, optional`): Realized PnL as a decimal string.
- `hash` (`string, optional`): Hyperliquid transaction hash.
- `oid` (`number, optional`): Hyperliquid order ID.
- `crossed` (`boolean, required`): Whether the order crossed the spread.
- `fee` (`string, optional`): User fee amount.
- `tid` (`number, optional`): Trade ID, when available.
- `feeToken` (`string, optional`): Token used to pay fees.
- `builder` (`string, optional`): Builder address, when present.
- `twapId` (`number, required`): TWAP order ID for the slice fill.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for stable by-time pagination.

## Successful Response

```json
[
  {
    "coin": "BTC",
    "px": "100.5",
    "sz": "0.25",
    "side": "B",
    "time": 1753606200000,
    "startPosition": "1.0",
    "dir": "Open Long",
    "closedPnl": "0",
    "hash": "0xabc",
    "oid": 1234,
    "crossed": false,
    "fee": "0.01",
    "tid": 99,
    "feeToken": "USDC",
    "builder": "0x2222222222222222222222222222222222222222",
    "twapId": 1755601,
    "txIndex": 8
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSliceFillsByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "userTwapSliceFillsByTime",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753606300000,
    "limit": 100
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

Each fill row is a normal fill object with `twapId` populated. For the next page, pass the last returned row's `time` and `txIndex` as `cursor`, for example `1753606200000_8`.

---

## userTwapSummaries - User TWAP Summaries

# userTwapSummaries - User TWAP Summaries

Use `userTwapSummaries` to retrieve recent execution-derived TWAP summaries for one Hyperliquid user address. Each summary aggregates indexed TWAP slice fills by `(user, twapId)`.

TWAP summaries are derived from executed slice fills in the Hyperliquid Index. They summarize observed executions, not the full parent TWAP order intent or configuration.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`userTwapSummaries` responses are billed by the number of TWAP summary objects returned, not as one response per HTTP request.
A response with `50` summaries counts as `50` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be userTwapSummaries for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `limit` (`number, optional`): Maximum summaries to return, capped at 500.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSummaries",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 100
}'
```

## Response Fields

- `summaries` (`array, required`): Array of execution-derived TWAP summary objects. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per summary object returned.
- `user` (`string, required`): User address.
- `twapId` (`number, required`): TWAP order ID.
- `coin` (`string, required`): Hyperliquid market symbol.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `avgPx` (`string, required`): Size-weighted average execution price as a decimal string.
- `sz` (`string, required`): Total executed size across indexed slices as a decimal string.
- `fee` (`string, required`): Total user fee across indexed slices as a decimal string.
- `closedPnl` (`string, required`): Total realized PnL across indexed slices as a decimal string.
- `nSlices` (`number, required`): Number of slice fill rows included in the summary.
- `firstFillTime` (`number, required`): Earliest slice fill timestamp in Unix milliseconds.
- `lastFillTime` (`number, required`): Latest slice fill timestamp in Unix milliseconds.
- `txIndex` (`number, optional`): Block-local fill event index for the latest slice in the summary.

## Successful Response

```json
[
  {
    "user": "0x1111111111111111111111111111111111111111",
    "twapId": 1755601,
    "coin": "BTC",
    "side": "B",
    "avgPx": "100.5",
    "sz": "0.25",
    "fee": "0.01",
    "closedPnl": "0",
    "nSlices": 2,
    "firstFillTime": 1753606200000,
    "lastFillTime": 1753606260000,
    "txIndex": 8
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSummaries",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "limit": 50
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "userTwapSummaries",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "limit": 50
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

Results are ordered newest first by `lastFillTime`, then `txIndex`, then `twapId`.

---

## userTwapSummariesByTime - User TWAP Summaries by Time

# userTwapSummariesByTime - User TWAP Summaries by Time

Use `userTwapSummariesByTime` to retrieve execution-derived TWAP summaries for one user inside a bounded time window. The service first aggregates indexed slice fills by `(user, twapId)` inside the requested window, then applies cursor pagination to the grouped summaries.

Cursor pages must repeat the same `startTime` and `endTime` used for the first page. Changing the window can change the grouped TWAP summaries.

TWAP summaries are derived from executed slice fills in the Hyperliquid Index. They summarize observed executions, not the full parent TWAP order intent or configuration.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`userTwapSummariesByTime` responses are billed by the number of TWAP summary objects returned, not as one response per HTTP request.
A response with `50` summaries counts as `50` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

`txIndex` is the block-local fill event index for the latest slice in the grouped summary. It is exposed as a stable summary pagination key together with `lastFillTime`.

## Request Parameters

- `type` (`string, required`): Must be userTwapSummariesByTime for /info REST requests. Omit this field for JSON-RPC.
- `user` (`string, required`): 0x-prefixed Hyperliquid user address.
- `coin` (`string, optional`): Exact Hyperliquid market symbol, for example BTC. When supplied, only rows for that market are returned.
- `startTime` (`number, required`): Inclusive Unix timestamp in milliseconds. Keep this value unchanged when following cursors.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds. Keep this value unchanged when following cursors.
- `cursor` (`string, optional`): Pagination cursor in lastFillTime_txIndex format. Resumes after that grouped summary.
- `limit` (`number, optional`): Maximum summaries to return, capped at 500.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSummariesByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753606300000,
  "limit": 100
}'
```

## Response Fields

- `summaries` (`array, required`): Array of execution-derived TWAP summary objects for the requested window. /info returns this array directly; JSON-RPC returns it under result. Empty matches return an empty array and are billed as 0 responses/API credits. Billing counts one response/API credit per summary object returned.
- `user` (`string, required`): User address.
- `twapId` (`number, required`): TWAP order ID.
- `coin` (`string, required`): Hyperliquid market symbol.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `avgPx` (`string, required`): Size-weighted average execution price as a decimal string for slice fills in the requested window.
- `sz` (`string, required`): Total executed size across indexed slices in the requested window as a decimal string.
- `fee` (`string, required`): Total user fee across indexed slices in the requested window as a decimal string.
- `closedPnl` (`string, required`): Total realized PnL across indexed slices in the requested window as a decimal string.
- `nSlices` (`number, required`): Number of slice fill rows included in the windowed summary.
- `firstFillTime` (`number, required`): Earliest slice fill timestamp in Unix milliseconds within the requested window.
- `lastFillTime` (`number, required`): Latest slice fill timestamp in Unix milliseconds within the requested window.
- `txIndex` (`number, optional`): Block-local fill event index for the latest slice in the summary. Use with lastFillTime for stable by-time pagination.

## Successful Response

```json
[
  {
    "user": "0x1111111111111111111111111111111111111111",
    "twapId": 1755601,
    "coin": "BTC",
    "side": "B",
    "avgPx": "100.5",
    "sz": "0.25",
    "fee": "0.01",
    "closedPnl": "0",
    "nSlices": 2,
    "firstFillTime": 1753606200000,
    "lastFillTime": 1753606260000,
    "txIndex": 8
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## REST-style Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userTwapSummariesByTime",
  "user": "0x1111111111111111111111111111111111111111",
  "coin": "BTC",
  "startTime": 1753606200000,
  "endTime": 1753609900000,
  "limit": 50
}'
```

## JSON-RPC Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "userTwapSummariesByTime",
  "params": {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "BTC",
    "startTime": 1753606200000,
    "endTime": 1753609900000,
    "limit": 50
  }
}'
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

Results are ordered oldest first by `lastFillTime`, then `txIndex`, then `twapId`. For the next page, pass the last returned row's `lastFillTime` and `txIndex` as `cursor`, for example `1753606260000_8`, and keep the original time window unchanged.

---

## OHLCV Data - Aggregated Candlestick Data

# OHLCV Data - Aggregated Candlestick Data

Pre-aggregated candlestick data (Open, High, Low, Close, Volume), also called klines, for Hyperliquid markets, served from a Dwellir endpoint (API key required) over REST, JSON-RPC, and WebSocket. Intervals are `1s`, `1m` (1-minute klines), and `5m`, and history starts on `2025-07-27`. Range queries return up to 5,000 candles per call.

## What is OHLCV Data?

OHLCV data aggregates individual fills into time-based candles that are easier to use for charting, technical analysis, portfolio monitoring, and strategy backtesting than raw execution streams.

This product is built from the same raw fill data Dwellir collects from Hyperliquid and stores canonically, then derives sparse `1s`, `1m`, and `5m` candles from that trade history.

The OHLCV endpoint is available now at `api-hyperliquid-index.n.dwellir.com`. It requires a Dwellir API key, the same key model used
across the platform.

The OHLCV archive starts at `2025-07-27T08:00:00Z`, which matches the first available `node_fills_by_block` archive entry. The backfill
is complete, so `1s`, `1m`, and `5m` candles are available from that point to the present. Candles are sparse: intervals with no trades have no candle.

## Available Intervals

| Interval | Description | Typical Use Case                                 |
| -------- | ----------- | ------------------------------------------------ |
| `1s`     | 1 second    | High-frequency analysis, microstructure research |
| `1m`     | 1 minute    | Intraday trading, execution review, dashboards   |
| `5m`     | 5 minutes   | Short-term trend analysis, higher-level charting |

Larger intervals are intentionally not materialized today. Clients can derive them from the shipped `1s`, `1m`, or `5m` candles.

## Available Markets

OHLCV data covers all Hyperliquid market types. Each type uses a different symbol format in the `market` parameter:

| Market type       | Symbol format  | Example                | How it works                                     |
| ----------------- | -------------- | ---------------------- | ------------------------------------------------ |
| **Perp** (native) | `ASSET`        | `BTC`, `ETH`, `SOL`    | Use the asset name directly                      |
| **Spot**          | `@INDEX`       | `@142`, `@1`, `@9`     | Use `@` followed by the pair's numeric index     |
| **HIP-3 perpDex** | `prefix:ASSET` | `hyna:ETH`, `xyz:AAPL` | Use the DEX prefix, a colon, then the asset name |

Spot markets use the `@INDEX` format (e.g. `@142` for UBTC/USDC), **not** the token name. The only exception is `PURR`, the sole canonical spot pair, which can be queried by name.

### Discovering market symbols

Use Dwellir's [Info Endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint) to look up valid symbols before querying candles.

| Market type       | Info Endpoint                                           | What to look for                                                            |
| ----------------- | ------------------------------------------------------- | --------------------------------------------------------------------------- |
| **Perp**          | [`meta`](https://www.dwellir.com/docs/hyperliquid/meta)          | Each entry's `name` field in the `universe` array (e.g. `"BTC"`)            |
| **Spot**          | [`spotMeta`](https://www.dwellir.com/docs/hyperliquid/spot-meta) | Each pair's `index` in the `universe` array — use as `@INDEX` (e.g. `@142`) |
| **HIP-3 perpDex** | [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs) | The first element of each `assetToStreamingOiCap` pair (e.g. `"hyna:ETH"`)  |

For full details on how to query these endpoints, see [Discovering Markets](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles#discovering-markets) in the `candles` docs.

If you need to map a market to the underlying Hyperliquid asset index, start from [`meta`](https://www.dwellir.com/docs/hyperliquid/meta), [`spotMeta`](https://www.dwellir.com/docs/hyperliquid/spot-meta), and [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs).

## Candle Schema

```text
s, i, t, T, o, h, l, c, v, q, n, x
```

| Field | Type           | Description                                                         |
| ----- | -------------- | ------------------------------------------------------------------- |
| `s`   | string         | Hyperliquid market symbol, for example `BTC`, `@142`, or `hyna:ETH` |
| `i`   | string         | Candle interval, one of `1s`, `1m`, `5m`                            |
| `t`   | integer        | Candle open time in Unix milliseconds                               |
| `T`   | integer        | Candle close time in Unix milliseconds                              |
| `o`   | decimal string | First trade price in interval                                       |
| `h`   | decimal string | Highest trade price in interval                                     |
| `l`   | decimal string | Lowest trade price in interval                                      |
| `c`   | decimal string | Last trade price in interval                                        |
| `v`   | decimal string | Total traded size in base units                                     |
| `q`   | decimal string | Total traded notional in quote units                                |
| `n`   | integer        | Number of contributing trades                                       |
| `x`   | boolean        | `true` when the candle is finalized, `false` when it is still open  |

## How to Use the Endpoint

Choose the transport that matches your workflow:

- [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles) for single-market REST lookups, JSON-RPC lookups, and WebSocket live updates
- [`candle ranges`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candle-ranges) for paginated historical pulls of one market and interval
- [`allCandles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/all-candles) for one live stream of changed candles across active markets
- [Full-History Exports](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/full-history-exports) for ready-made CSV or Parquet files of the full archive for one market and interval
- [Archive backfill guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-archive-backfill) for DIY historical retrieval of one market and one interval
- [CSV export guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-csv-export) for DIY flat-file extraction by market and interval
- [Parquet export guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-parquet-export) for DIY columnar analytics exports

Current product contract:

- REST returns one candle per request
- JSON-RPC returns one candle per request
- candle range REST and JSON-RPC endpoints return paginated `data` arrays and bill by the number of candle objects returned
- WebSocket streams live candle state after subscribe with `wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY`; `wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/ws` is also accepted
- `allCandles` WebSocket streams emit arrays of changed candle snapshots and bill by the number of candle objects delivered in each data frame

## Sparse Candles

Only intervals with trading activity are materialized. Empty intervals are omitted rather than emitted as zero-volume carry-forward
candles.

This means:

- the dataset preserves real trading activity instead of synthesizing flat bars
- downstream consumers that need dense chart series can fill missing intervals on their side
- response counting for historical retrieval should assume one response per existing candle, not one response per theoretical time bucket

## Worked Example: 3 Months of 1-Minute Candles for One Market

Pulling 3 months (90 days) of `1m` candles for one market, for example BTC, looks like this:

- **Candles**: at most `90 x 1,440 = 129,600`. Candles are sparse, so a market with quiet minutes returns fewer.
- **Calls**: about `26` [candle range](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candle-ranges) calls at `limit=5000`, following `nextCursor` until `hasMore` is `false`.
- **API credits**: range pages bill 1 credit per returned candle, so at most `129,600` credits. On the Developer plan's 25 million included responses, that is about 0.5% of the monthly allowance.

The official Hyperliquid `candleSnapshot` info request only returns the most recent 5,000 candles, which is about 3.5 days of `1m` candles. Dwellir range queries page back to `2025-07-27`.

To get the same 3 months as one file instead, a [full-history export](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/full-history-exports) returns the whole archive for one market and interval for 1 export credit.

## Rate Limits

Dwellir API plans set these rate limits, measured in responses per second. See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits) for burst behavior and handling `429` errors.

| Plan                  | Responses per second | Burst  |
| --------------------- | -------------------- | ------ |
| Free                  | 20                   | None   |
| Developer ($49/month) | 100                  | 500    |
| Growth ($299/month)   | 500                  | 2,500  |
| Scale ($999/month)    | 5,000                | 10,000 |

See [pricing](https://www.dwellir.com/pricing) for included responses and overage rates per plan.

## Response Volume for One Market Over 30 Days

Single-candle REST and JSON-RPC requests return one candle per response. For large historical windows, use candle ranges so each page can include up to `5000` returned candle objects while billing still counts the candle objects in `data`.

| Interval | Approximate candles in 30 days | Single-candle responses | Range pages at limit `5000` |
| -------- | ------------------------------ | ----------------------- | --------------------------- |
| `1s`     | `2,592,000`                    | `2,592,000`             | about `519` pages           |
| `1m`     | `43,200`                       | `43,200`                | about `9` pages             |
| `5m`     | `8,640`                        | `8,640`                 | about `2` pages             |

Sparse gaps lower the actual returned candle count and therefore lower the billable weight.

## Example Candle

```json
{
  "s": "BTC",
  "i": "1m",
  "t": 1774911600000,
  "T": 1774911659999,
  "o": "66745",
  "h": "66746",
  "l": "66687",
  "c": "66687",
  "v": "4.78586",
  "q": "319316.665",
  "n": 256,
  "x": true
}
```

## Data Quality

- **Accuracy**: Derived from canonical raw fill history
- **Consistency**: One schema across all shipped intervals and transports
- **Recency**: Historical backfill plus live candle upkeep

### Note on Sweep Executions

In fast markets, one large order can trade through several price levels in a single sweep. When candles are derived from raw fill data, those exact match prices are preserved, which can occasionally produce slightly different highs or lows than a venue's own public candlestick feed.

Think of the book like this:

- ask at `69344`
- ask at `69343`
- then one aggressive order arrives and buys through both levels

In one BTC 5-minute bar we validated, that sweep matched:

- `0.08487 BTC` at `69344`
- `0.34059 BTC` at `69343`

If you keep the exact fill prices, the candle for that slice is:

- `low = 69343`
- `volume = 0.42546 BTC`

From our benchmarking against the public Hyperliquid endpoint, it appears that their candlestick feed compresses some sweeps differently. We base our candles directly on node fills and preserve the executed prices instead of re-aggregating that move away, so the same sweep can appear as:

- `low = 69344`
- `volume = 0.42546 BTC`

This is intentional. Dwellir candles are built from the underlying node fill stream, so highs, lows, and volume reflect the executed prices we observe rather than a more compressed candle representation. That can produce small high or low differences versus another public feed, but it is the more execution-faithful view of what actually traded.

## Related Data Products

| Need                                      | Recommendation                                           |
| ----------------------------------------- | -------------------------------------------------------- |
| Individual trade executions               | [Tick Data](https://www.dwellir.com/docs/hyperliquid/tick-data) |
| Raw archive / full historical source data | [Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)     |
| Native Hyperliquid L1 fill streaming      | [StreamFills gRPC](https://www.dwellir.com/docs/hyperliquid/stream_fills)  |

## Access

Use your Dwellir API key directly against the OHLCV host for live candle lookups and WebSocket streams. For historical OHLCV exports covering all markets with full archive depth, use the dashboard export feature.

- **[Sign up](https://dashboard.dwellir.com/register)** at the dashboard, then visit the **[OHLCV Data tab](https://dashboard.dwellir.com/hyperliquid?tab=ohlcv)** to buy export credits and generate CSV or Parquet files for any market at 1s, 1m, or 5m intervals.
- Pricing: [dwellir.com/pricing](https://www.dwellir.com/pricing). API plans start at $49/month (Developer), and 1 response = 1 API credit.

---

## Hyperliquid allCandles WebSocket API

# Hyperliquid allCandles WebSocket API

Use `allCandles` when you want one live stream of candle changes across every active Hyperliquid market for a single interval. The stream is sparse: each data frame contains only markets that emitted a candle update for that batch.

If you need one specific market, use [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles).

The `allCandles` stream is not a historical replay API. It starts delivering live batches after a successful subscription.

## Billing

`allCandles` WebSocket data frames are billed by the number of candle objects delivered in `data`, not as one response per WebSocket
frame. A frame with `87` candle objects counts as `87` responses.

Sparse markets that do not emit a candle object in a frame do not add to the response count. Subscription acknowledgements and other control messages establish the stream but do not add candle responses.

## Endpoint

```text
wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY
```

If your client expects an explicit WebSocket path, this compatible form also works:

```text
wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/ws
```

## Subscribe Message

Send a subscribe message with `subscription.type` set to `allCandles`. Unlike the single-market stream, this subscription does not include `market`.

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "allCandles",
    "interval": "1m"
  }
}
```

Supported intervals are `1s`, `1m`, and `5m`.

### Subscription Parameters

| Parameter               | Type   | Required | Description                                                      |
| ----------------------- | ------ | -------- | ---------------------------------------------------------------- |
| `method`                | string | Yes      | Must be `"subscribe"`                                            |
| `subscription.type`     | string | Yes      | Must be `"allCandles"`                                           |
| `subscription.interval` | string | Yes      | Candle interval. Supported values are `"1s"`, `"1m"`, and `"5m"` |

## Request Parameters

- `method` (`string, required`): Must be `"subscribe"`
- `subscription.type` (`string, required`): Must be `"allCandles"`
- `subscription.interval` (`string, required`): Candle interval: `"1s"`, `"1m"`, or `"5m"`

## Request Example

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "allCandles",
    "interval": "1m"
  }
}
```

## Response Fields

- `type` (`string, required`): Always `"allCandles"` for data messages
- `seq` (`number, required`): Per-subscription sequence number
- `cursor` (`string, required`): Candle open time encoded as Unix milliseconds
- `data` (`array, required`): Array of emitted candle objects. Billing counts one response per candle object in this array.
- `data[].s` (`string, required`): Hyperliquid market symbol
- `data[].i` (`string, required`): Candle interval
- `data[].t` (`number, required`): Candle open time in Unix milliseconds
- `data[].T` (`number, required`): Candle close time in Unix milliseconds
- `data[].o` (`string, required`): First trade price in the interval
- `data[].h` (`string, required`): Highest trade price in the interval
- `data[].l` (`string, required`): Lowest trade price in the interval
- `data[].c` (`string, required`): Last trade price in the interval
- `data[].v` (`string, required`): Total traded size in base units
- `data[].q` (`string, required`): Total traded notional in quote units
- `data[].n` (`number, required`): Number of contributing trades
- `data[].x` (`boolean, required`): Candle finalization flag

## Successful Response

```json
{
  "type": "allCandles",
  "seq": 12,
  "cursor": "1775601060000",
  "data": [
    {
      "s": "BTC",
      "i": "1m",
      "t": 1775601060000,
      "T": 1775601119999,
      "o": "71564",
      "h": "71578",
      "l": "71563",
      "c": "71577",
      "v": "0.21291",
      "q": "15238.32632",
      "n": 57,
      "x": false
    },
    {
      "s": "ETH",
      "i": "1m",
      "t": 1775601060000,
      "T": 1775601119999,
      "o": "3864.2",
      "h": "3865.1",
      "l": "3863.9",
      "c": "3864.8",
      "v": "14.893",
      "q": "57555.8064",
      "n": 31,
      "x": false
    }
  ]
}
```

## Example Flow

Client sends:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "allCandles",
    "interval": "1m"
  }
}
```

Server acknowledges:

```json
{
  "type": "subscribed",
  "interval": "1m",
  "subscriptionType": "allCandles"
}
```

Then sends `allCandles` events. Each event contains a `data` array of candle objects:

```json
{
  "type": "allCandles",
  "seq": 12,
  "cursor": "1775601060000",
  "data": [
    {
      "s": "BTC",
      "i": "1m",
      "t": 1775601060000,
      "T": 1775601119999,
      "o": "71564",
      "h": "71578",
      "l": "71563",
      "c": "71577",
      "v": "0.21291",
      "q": "15238.32632",
      "n": 57,
      "x": false
    },
    {
      "s": "ETH",
      "i": "1m",
      "t": 1775601060000,
      "T": 1775601119999,
      "o": "3864.2",
      "h": "3865.1",
      "l": "3863.9",
      "c": "3864.8",
      "v": "14.893",
      "q": "57555.8064",
      "n": 31,
      "x": false
    }
  ]
}
```

## Response Field Reference

| Field    | Description                                                                                                          |
| -------- | -------------------------------------------------------------------------------------------------------------------- |
| `seq`    | Per-subscription sequence number. Starts at `1` for the first `allCandles` event and increases on every data message |
| `cursor` | Candle open time encoded as a Unix millisecond timestamp string                                                      |
| `data`   | Array of candle objects emitted for the batch                                                                        |
| `data.s` | Hyperliquid market symbol, for example `BTC`, `@142`, or `hyna:ETH`                                                  |
| `data.i` | Candle interval, one of `1s`, `1m`, `5m`                                                                             |
| `data.t` | Candle open time in Unix milliseconds                                                                                |
| `data.T` | Candle close time in Unix milliseconds                                                                               |
| `data.o` | First trade price in the interval                                                                                    |
| `data.h` | Highest trade price in the interval                                                                                  |
| `data.l` | Lowest trade price in the interval                                                                                   |
| `data.c` | Last trade price in the interval                                                                                     |
| `data.v` | Total traded size in base units                                                                                      |
| `data.q` | Total traded notional in quote units                                                                                 |
| `data.n` | Number of contributing trades                                                                                        |
| `data.x` | Candle finalization flag. `false` means the candle is still open and `true` means it is finalized                    |

## Behavior

- subscription is keyed by `interval`
- the stream emits arrays of changed candle snapshots across active markets
- each frame contains only markets with a candle update in that batch
- `seq` is per-subscription ordering and starts at `1` for the first `allCandles` event
- `cursor` is the candle open time encoded as a Unix millisecond timestamp string
- candle payloads use the same `s i t T o h l c v q n x` schema as REST, JSON-RPC, and the single-market WebSocket stream
- `x=false` means the candle is still open, and `x=true` means it is finalized

## Authentication

- include your Dwellir API key in the WebSocket path: `wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY`
- `wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/ws` is also accepted for clients that expect an explicit WebSocket path
- both forms connect to the same live `allCandles` stream

## When to Use allCandles

- full-market dashboards
- alerting systems that scan every active market
- analytics pipelines that need one interval-wide stream instead of one WebSocket subscription per market

---

## Hyperliquid candle ranges

# Hyperliquid candle ranges

Use candle ranges when you need many historical candles for one Hyperliquid market without iterating the single-candle endpoint one bucket at a time.

| Transport | Best for                             | Endpoint                                     |
| --------- | ------------------------------------ | -------------------------------------------- |
| REST      | Simple paginated historical pulls    | `GET /v1/candles/range`                      |
| JSON-RPC  | Method-based clients and RPC logging | `POST /jsonrpc` with `ohlcv_getCandlesRange` |

Successful non-empty range pages are billed by the number of candle objects in `data`, not as one flat request. Empty successful
sparse ranges are not billed.

`start` is inclusive and `end` is exclusive. Use `start=2025-10-01T00:00:00Z&end=2025-11-01T00:00:00Z` for a clean October 2025
range.

ze. Defaults to `2000` and is capped at `5000`. |
\| `cursor` | no | Opaque cursor returned as `nextCursor` from the previous page. |

`start`, `end`, and `cursor` must align to the requested interval. Requests that include the current in-progress bucket or a future bucket fail rather than returning provisional candles.

## Request Parameters

- `market` (`string, required`): Hyperliquid market symbol, for example `"BTC"`, `"@142"`, or `"hyna:ETH"`.
- `interval` (`string, required`): Candle interval, one of `"1s"`, `"1m"`, or `"5m"`.
- `start` (`string, optional`): Inclusive ISO-8601 UTC lower bound aligned to the interval.
- `end` (`string, optional`): Exclusive ISO-8601 UTC upper bound aligned to the interval.
- `limit` (`number, optional`): Page size. Defaults to `2000` and is capped at `5000`.
- `cursor` (`string, optional`): Opaque cursor returned as `nextCursor` by the previous page.

## Request Example

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles/range?market=BTC&interval=1s&start=2025-10-01T00:00:00Z&end=2025-11-01T00:00:00Z&limit=5000"
```

## Response Fields

- `data` (`array, required`): Array of returned sparse candle objects. Billing counts one response per object in this array.
- `data[].s` (`string, required`): Hyperliquid market symbol.
- `data[].i` (`string, required`): Candle interval.
- `data[].t` (`number, required`): Candle open time in Unix milliseconds.
- `data[].T` (`number, required`): Candle close time in Unix milliseconds.
- `data[].o` (`string, required`): First trade price in the interval.
- `data[].h` (`string, required`): Highest trade price in the interval.
- `data[].l` (`string, required`): Lowest trade price in the interval.
- `data[].c` (`string, required`): Last trade price in the interval.
- `data[].v` (`string, required`): Total traded size in base units.
- `data[].q` (`string, required`): Total traded notional in quote units.
- `data[].n` (`number, required`): Number of contributing trades.
- `data[].x` (`boolean, required`): Candle finalization flag. Historical range responses return finalized candles with `x=true`.
- `nextCursor` (`string, optional`): Cursor for the next page. Present only when `hasMore=true`.
- `hasMore` (`boolean, required`): Whether another page is available.

## Successful Response

```json
{
  "data": [
    {
      "s": "BTC",
      "i": "1s",
      "t": 1759276800000,
      "T": 1759276800999,
      "o": "117845",
      "h": "117862",
      "l": "117840",
      "c": "117851",
      "v": "3.48221",
      "q": "410385.79284",
      "n": 42,
      "x": true
    }
  ],
  "nextCursor": "1759276801000",
  "hasMore": true
}
```

## Error Responses

### Invalid range

- Code: `400 / -32602`
- Description: Invalid interval, malformed timestamp, non-aligned timestamp, malformed cursor, or `end` before `start`.

### Current or future bucket

- Code: `400 / -32001`
- Description: The requested `end` includes the current in-progress bucket or a future bucket.

## REST

```text
GET https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles/range
```

Fetch BTC `1s` candles for October 2025:

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles/range?market=BTC&interval=1s&start=2025-10-01T00:00:00Z&end=2025-11-01T00:00:00Z&limit=5000"
```

REST returns a paginated envelope. Continue while `hasMore` is `true` by sending the returned `nextCursor`:

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles/range?market=BTC&interval=1s&end=2025-11-01T00:00:00Z&limit=5000&cursor=1759276801000"
```

## JSON-RPC

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

Method:

```text
ohlcv_getCandlesRange
```

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "ohlcv_getCandlesRange",
    "params": {
      "market": "BTC",
      "interval": "1m",
      "start": "2025-10-01T00:00:00Z",
      "end": "2025-11-01T00:00:00Z",
      "limit": 5000
    }
  }'
```

JSON-RPC returns the same range page under `result`.

zed candle objects. |
\| `nextCursor` | Cursor for the next page. Present only when `hasMore=true`. |
\| `hasMore` | `true` when another page is available. |

## Sparse Range Behavior

Candles are sparse. The API returns only stored candles with trading activity and does not synthesize zero-volume carry-forward intervals.

An empty sparse range returns:

```json
{
  "data": [],
  "hasMore": false
}
```

Empty successful ranges do not include `X-Iris-Billing-Weight`.

## Billing

Range pages use backend-signaled row billing:

- `X-Iris-Billing-Weight: <len(data)>` on successful non-empty REST and JSON-RPC pages
- no billing header on empty successful pages
- no billing header on error responses
- sparse gaps do not count toward billing

For example, if a requested `1s` month contains `1,800,000` stored candles, only those returned candle objects are billed across the pages you actually fetch.

## When to Use Candle Ranges

- backfilling one market into a charting store
- retrieving full-month or full-day candle windows
- resuming long historical jobs with cursor pagination
- pulling all available sparse candles for a market and interval

For one known candle timestamp, use [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles). For live all-market updates, use [`allCandles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/all-candles).

---

## Hyperliquid Index OHLCV candles API

# Hyperliquid Index OHLCV candles API

Use `candles` when you need OHLCV data for one Hyperliquid market and one interval. The same candle schema is available over REST, JSON-RPC, and WebSocket:

| Transport | Best for                                                                     | Endpoint                                                 |
| --------- | ---------------------------------------------------------------------------- | -------------------------------------------------------- |
| REST      | Simple HTTP lookups for a known timestamp or for the latest finalized candle | `GET /v1/candles`                                        |
| JSON-RPC  | Clients that prefer method-based RPC envelopes                               | `POST /jsonrpc` with `ohlcv_getCandle`                   |
| WebSocket | Live candle state updates after subscribing                                  | `wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY` |

Historical candle lookups are intended to cover history back to `2025-07-27T08:00:00Z`, which is the first available
`node_fills_by_block` archive hour.

The WebSocket surface is not a historical replay API. It streams live candle updates after a successful subscription, including
in-progress candles before they finalize.

Z`. Omit `time`to return the latest finalized candle for the requested`market`and`interval`. | | `type`| WebSocket only | Must be`subscribe\` for the WebSocket subscribe message. |

## Request Parameters

- `market` (`string, required`): Hyperliquid market symbol, for example `"BTC"`, `"@142"`, or `"hyna:ETH"`.
- `interval` (`string, required`): Candle interval, one of `"1s"`, `"1m"`, or `"5m"`.
- `time` (`string, optional`): Required for REST and JSON-RPC historical lookups. Candle bucket-open timestamp in ISO-8601 UTC.
- `type` (`string, optional`): Required for WebSocket subscriptions. Must be `"subscribe"`.

## Request Example

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles?market=BTC&interval=1m&time=2026-03-30T23:00:00Z"
```

## Response Fields

- `s` (`string, required`): Hyperliquid market symbol.
- `i` (`string, required`): Candle interval.
- `t` (`number, required`): Candle open time in Unix milliseconds.
- `T` (`number, required`): Candle close time in Unix milliseconds.
- `o` (`string, required`): First trade price in the interval.
- `h` (`string, required`): Highest trade price in the interval.
- `l` (`string, required`): Lowest trade price in the interval.
- `c` (`string, required`): Last trade price in the interval.
- `v` (`string, required`): Total traded size in base units.
- `q` (`string, required`): Total traded notional in quote units.
- `n` (`number, required`): Number of contributing trades.
- `x` (`boolean, required`): Candle finalization flag.

## Successful Response

```json
{
  "s": "BTC",
  "i": "1m",
  "t": 1774911600000,
  "T": 1774911659999,
  "o": "66745",
  "h": "66746",
  "l": "66687",
  "c": "66687",
  "v": "4.78586",
  "q": "319316.665",
  "n": 256,
  "x": true
}
```

## Error Responses

### Sparse bucket not found

- Code: `404 / -32004`
- Description: REST returns 404 and JSON-RPC returns -32004 when no candle exists for a sparse historical bucket.

## REST

Use REST when you want a simple HTTP lookup for one completed candle.

```text
GET https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles
```

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles?market=BTC&interval=1m&time=2026-03-30T23:00:00Z"
```

Omit `time` to return the latest finalized candle for the requested `market` and `interval`:

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/v1/candles?market=BTC&interval=1m"
```

REST returns the candle object directly. Missing sparse buckets return `404`.

## JSON-RPC

Use JSON-RPC when your client already expects RPC envelopes or method-based request logging.

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

Method:

```text
ohlcv_getCandle
```

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "ohlcv_getCandle",
    "params": {
      "market": "BTC",
      "interval": "1m",
      "time": "2026-03-30T23:00:00Z"
    }
  }'
```

Omit `time` from `params` to return the latest finalized candle for the requested `market` and `interval`:

```bash
curl "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc" \
  -H "content-type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "ohlcv_getCandle",
    "params": {
      "market": "BTC",
      "interval": "1m"
    }
  }'
```

JSON-RPC returns the candle object under `result`. Missing sparse buckets return an error with `code: -32004`.

## WebSocket

Use WebSocket when you want live candle updates pushed to your client for one market and interval.

```text
wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY
```

If your client expects an explicit WebSocket path, this compatible form also works:

```text
wss://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/ws
```

Send a subscribe message:

```json
{ "type": "subscribe", "market": "BTC", "interval": "1m" }
```

The stream includes both unfinalized updates and the final closed candle state. Repeated messages with the same `cursor` are successive states of the same candle.

If you need one interval-wide stream for all active markets, use [`allCandles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/all-candles).

## Candle Field Reference

| Field | Description                                                                                                                                                             |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `s`   | Hyperliquid market symbol, for example `BTC`, `@142`, or `hyna:ETH`.                                                                                                    |
| `i`   | Candle interval, one of `1s`, `1m`, `5m`.                                                                                                                               |
| `t`   | Candle open time in Unix milliseconds.                                                                                                                                  |
| `T`   | Candle close time in Unix milliseconds.                                                                                                                                 |
| `o`   | First trade price in the interval.                                                                                                                                      |
| `h`   | Highest trade price in the interval.                                                                                                                                    |
| `l`   | Lowest trade price in the interval.                                                                                                                                     |
| `c`   | Last trade price in the interval.                                                                                                                                       |
| `v`   | Total traded size in base units.                                                                                                                                        |
| `q`   | Total traded notional in quote units.                                                                                                                                   |
| `n`   | Number of contributing trades.                                                                                                                                          |
| `x`   | Candle finalization flag. Historical REST and JSON-RPC lookups return completed candles with `x=true`; WebSocket updates can be `false` while the candle is still open. |

## Discovering Markets

Use Dwellir's [Info Endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint) to find valid `market` values before querying candles.

### Native perp symbols

Call [`meta`](https://www.dwellir.com/docs/hyperliquid/meta). Each entry's `name` in the `universe` array is the symbol you need.

```bash
curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info' \
  -H 'Content-Type: application/json' \
  -d '{"type":"meta"}'
```

Look for entries like `{ "name": "BTC", "szDecimals": 5, "maxLeverage": 40 }` and use `market=BTC`.

### Spot symbols

Call [`spotMeta`](https://www.dwellir.com/docs/hyperliquid/spot-meta). Each pair in the `universe` array has an `index` field. Prefix it with `@` to get the market symbol.

```bash
curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info' \
  -H 'Content-Type: application/json' \
  -d '{"type":"spotMeta"}'
```

To find a specific token's spot pair, cross-reference the `tokens` and `universe` arrays:

```python
import requests

data = requests.post(
    "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info",
    json={"type": "spotMeta"},
).json()

tokens = {t["index"]: t for t in data["tokens"]}

for pair in data["universe"]:
    t0, t1 = pair["tokens"]
    if "BTC" in tokens[t0]["name"].upper():
        symbol = pair["name"] if pair.get("isCanonical") else f"@{pair['index']}"
        print(f"Use market={symbol}")  # market=@142
```

### HIP-3 perpDex symbols

Call [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs). Each DEX has an `assetToStreamingOiCap` array of `[symbol, oiCap]` pairs. The symbol is what you pass as `market`.

```bash
curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info' \
  -H 'Content-Type: application/json' \
  -d '{"type":"perpDexs"}'
```

Some HIP-3 DEXs currently available:

| Prefix | Name               | Example assets               |
| ------ | ------------------ | ---------------------------- |
| `xyz`  | XYZ                | `xyz:AAPL`, `xyz:GOLD`       |
| `flx`  | Felix Exchange     | `flx:COPPER`, `flx:COIN`     |
| `hyna` | HyENA              | `hyna:BTC`, `hyna:ETH`       |
| `km`   | Markets by Kinetiq | `km:AAPL`, `km:BMNR`         |
| `cash` | dreamcash          | `cash:EWY`, `cash:GOLD`      |
| `para` | Paragon            | `para:TOTAL2`, `para:OTHERS` |

## Behavior

- REST and JSON-RPC return one completed candle per request.
- `time` is the open time of the candle bucket, not an arbitrary point inside a range.
- Omit `time` on REST or JSON-RPC to return the latest finalized candle for the requested `market` and `interval`.
- WebSocket streams live candle state after subscribe.
- Candle payloads use the same `s i t T o h l c v q n x` schema across all three transports.
- Candles are sparse. Empty intervals are omitted instead of forward-filled.

## Fetching Multiple Historical Candles

For large contiguous historical pulls, use [`candle ranges`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candle-ranges). Range pages return arrays of the same candle objects and bill by the number of returned candles.

Use the `time` parameter as the iterator only when you specifically need the single-candle endpoint. For `1m`, advance by one minute per request. For `5m`, advance by five minutes. For `1s`, advance by one second.

For high-throughput backfills, see the [archive backfill guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-archive-backfill). It covers HTTP/2, worker pools, sticky-session discovery, rate limiting, sparse bucket handling, and atomic resume state.

## When to Use Each Transport

| Need                                       | Recommendation                                                                              |
| ------------------------------------------ | ------------------------------------------------------------------------------------------- |
| One known historical candle                | REST                                                                                        |
| The latest finalized candle for one market | REST or JSON-RPC without `time`                                                             |
| RPC-style envelopes and method logs        | JSON-RPC                                                                                    |
| Live updates for one market                | WebSocket                                                                                   |
| Live updates across all active markets     | [`allCandles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/all-candles)                  |
| Full archive as a ready-made file          | [Full-history exports](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/full-history-exports) |

---

## Hyperliquid OHLCV Full-History Exports

# Hyperliquid OHLCV Full-History Exports

Download the complete Hyperliquid OHLCV archive for one market and one candle interval as a single ready-made file. Exports are generated on demand from the Dwellir dashboard and delivered as either gzipped CSV or Parquet.

Use this when you need the full archive as one file and do not want to build your own fetcher. For single candle lookups, arbitrary time windows, or live candle updates, use [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles) instead.

Full-history exports are generated from [dashboard.dwellir.com](https://dashboard.dwellir.com) on the **Hyperliquid** page
under the **OHLCV Data** tab. The candle schema matches the live OHLCV endpoint exactly.

## What You Get

Each export is a single file containing every candle for one market at one interval, covering the full available archive in one pass.

| Attribute       | Value                                                             |
| --------------- | ----------------------------------------------------------------- |
| Formats         | `CSV` (gzipped, `.csv.gz`) or `Parquet` (`.parquet`)              |
| Intervals       | `1s`, `1m`, `5m`                                                  |
| Markets         | All indexed Hyperliquid markets — perps, spot, and HIP-3 perpDexs |
| Coverage start  | Same archive floor as the live endpoint: `2025-07-27T08:00:00Z`   |
| Coverage end    | Latest available candle at the time of generation                 |
| Sort order      | Ascending by candle open time (`t`)                               |
| Sparse handling | Empty intervals are omitted, matching the live product contract   |
| Retention       | Downloads remain available for 30 days after generation           |

The column schema is identical to the [live OHLCV endpoint](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data#candle-schema): `s, i, t, T, o, h, l, c, v, q, n, x`. Prices and volumes are serialized as decimal strings in both formats so that precision is preserved end to end.

## How to Generate an Export

1. Sign in at [dashboard.dwellir.com](https://dashboard.dwellir.com) and open the **Hyperliquid** page from the sidebar.
2. Switch to the **OHLCV Data** tab. You will see a searchable catalog of every indexed market, its coverage window, and its duration.
3. Find the market you want. Use the search box to filter by name (for perps, use the asset name such as `BTC`; spot markets are searchable by their decoded ticker) or the filter chips for `Perp`, `Spot`, or a specific HIP-3 DEX prefix.
4. Click **Generate** on the row. Pick the interval (`1s`, `1m`, `5m`) and format (`CSV` or `Parquet`) in the modal.
5. Click **Generate export**. Progress appears in place; you can close the modal and return later — polling continues in the background, and the completed artifact is listed on the OHLCV Data tab when it is ready.
6. When generation completes, click **Download** to save the file. Re-downloads from the same run are free.

Large exports — for example full `1s` history for a liquid perp — may take several minutes. Credits are reserved when you click **Generate**, and successful downloads are available for 30 days.

## File Naming

Exports use a predictable file name so you can script downstream processing:

```text
{market}-{interval}-full.csv.gz
{market}-{interval}-full.parquet
```

Market names are sanitized to the `[A-Za-z0-9_-]` character set and lower-cased. Any other characters — for example the `@` prefix on spot indexes or the `:` separator on HIP-3 prefixes — are replaced with `-` and stripped from the ends.

| Market     | Interval | Format  | Filename                   |
| ---------- | -------- | ------- | -------------------------- |
| `BTC`      | `1m`     | CSV     | `btc-1m-full.csv.gz`       |
| `@142`     | `5m`     | Parquet | `142-5m-full.parquet`      |
| `hyna:ETH` | `1s`     | Parquet | `hyna-eth-1s-full.parquet` |

## Working With the Files

### CSV

The CSV is gzip-compressed with a single header row followed by one row per candle.

```bash
gunzip -c btc-1m-full.csv.gz | head
```

Load it directly with pandas:

```python
import pandas as pd

df = pd.read_csv("btc-1m-full.csv.gz", compression="gzip")
```

### Parquet

The Parquet file is a single columnar output readable by DuckDB, pandas, Spark, and most analytics engines.

```python
import pandas as pd

df = pd.read_parquet("btc-1m-full.parquet")
```

Or in DuckDB:

```sql
SELECT *
FROM read_parquet('btc-1m-full.parquet')
ORDER BY t
LIMIT 10;
```

## Credits and Pricing

Exports are paid for with OHLCV export credits, purchased from the OHLCV Data tab. One credit covers one export — one market at one interval in one format.

- **Graduated per-credit pricing.** Credits get cheaper per unit as you buy more.
- **Unlimited option.** Teams that need the full catalog can switch to an unlimited tier that removes the per-export credit charge.
- **Re-downloads are free.** Credits are consumed when you start an export; downloading the resulting file during the 30-day retention window does not cost additional credits.
- **30-day retention.** Artifacts and their download links expire 30 days after a successful generation. Re-generate after expiry to refresh an archive.

Current prices and the credit slider are available on the OHLCV Data tab in the dashboard.

## When to Use This vs. the API

| Need                                                                                   | Recommendation                                                                                                                                                                                      |
| -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Full history for one market and interval as one file, no fetcher to build              | Full-history exports (this page)                                                                                                                                                                    |
| Specific candles or arbitrary time windows on demand                                   | [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles) over REST or JSON-RPC                                                                                                           |
| Live candle updates                                                                    | [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles) over WebSocket                                                                                                                  |
| Custom fetch loop, own storage layout, or stream straight into a pipeline              | [Archive backfill guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-archive-backfill), [CSV export guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-csv-export), or [Parquet export guide](https://www.dwellir.com/guides/hyperliquid-ohlcv-parquet-export) |
| Raw L1 data (fills, order book diffs, replica commands) rather than aggregated candles | [Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)                                                                                                                                                |

## Access

- **[Sign up](https://dashboard.dwellir.com/register)** at the dashboard, then visit the **[OHLCV Data tab](https://dashboard.dwellir.com/hyperliquid?tab=ohlcv)** to buy export credits and start generating exports.
- Pricing overview: [dwellir.com/pricing](https://www.dwellir.com/pricing)

---

## HIP-4 Outcome Markets

# HIP-4 Outcome Markets

HIP-4 adds outcome markets to HyperCore. Dwellir's Hyperliquid Index exposes outcome metadata, lifecycle events, and outcome-side fills through the same REST-style `/info` and JSON-RPC surfaces used by indexed fills and candles.

Use these methods when you need to discover active outcomes, backfill registration and settlement history, or retrieve fills for outcome instruments such as `#30` and `#31`.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

For `/info`, set `type` to the method name. For JSON-RPC, set `method` to the same value and pass request fields under `params`.

## Outcome Asset IDs

HIP-4 outcome sides are encoded as `#<encoding>` coins:

| Value       | Meaning                                            |
| ----------- | -------------------------------------------------- |
| `outcomeId` | Numeric outcome ID assigned in registration order. |
| `side`      | `yes`, `no`, `0`, or `1`.                          |
| `Yes` coin  | `#(10 * outcomeId)`.                               |
| `No` coin   | `#(10 * outcomeId + 1)`.                           |

For outcome ID `3`, the Yes side is `#30` and the No side is `#31`.

## Methods

| Method                                                                                                        | Use case                                                       |
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| [`outcomeMeta`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/outcome-meta)                             | Current active outcome metadata and `sideSpecs`.               |
| [`outcomeFills`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/outcome-fills)                           | Recent fills for all outcome coins or one outcome side.        |
| [`outcomeFillsByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/outcome-fills-by-time)             | Outcome fills inside a bounded time window.                    |
| [`registeredOutcomes`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/registered-outcomes)               | Recent registered outcomes that have not settled yet.          |
| [`registeredOutcomesByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/registered-outcomes-by-time) | Registered outcomes inside a bounded registration-time window. |
| [`registeredOutcomesById`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/registered-outcomes-by-id)     | Registered outcomes by `outcome_ids` or `asset_ids`.           |
| [`settledOutcomes`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/settled-outcomes)                     | Recent settled outcomes.                                       |
| [`settledOutcomesByTime`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/settled-outcomes-by-time)       | Settled outcomes inside a bounded settlement-time window.      |
| [`settledOutcomesById`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/outcome-markets/settled-outcomes-by-id)           | Settled outcomes by `outcome_ids` or `asset_ids`.              |

## Billing

Outcome fill and outcome lifecycle list responses are billed by returned objects through `X-Iris-Billing-Weight`.

| Method family                             | Billing weight                                                        |
| ----------------------------------------- | --------------------------------------------------------------------- |
| `outcomeFills`, `outcomeFillsByTime`      | Number of returned fill objects.                                      |
| `registeredOutcomes*`, `settledOutcomes*` | Number of returned outcome objects.                                   |
| `outcomeMeta`                             | Regular single metadata response; no bundled-response billing header. |

Empty arrays return billing weight `0`. Error responses are not charged.

## Pagination

By-time methods page oldest to newest:

| Method family              | Cursor format    | Sort key                                  |
| -------------------------- | ---------------- | ----------------------------------------- |
| `outcomeFillsByTime`       | `time_txIndex`   | Fill timestamp, then fill `txIndex`.      |
| `registeredOutcomesByTime` | `time_outcomeId` | Registration event time, then outcome ID. |
| `settledOutcomesByTime`    | `time_outcomeId` | Settlement event time, then outcome ID.   |

When `cursor` is supplied, the service resumes after the cursor and ignores `startTime`. Keep the same `endTime` across pages for a stable window.

## Indexing Model

Dwellir derives these endpoints from Hyperliquid L1 data and stores the customer-facing records needed for serving queries:

- outcome registration and settlement events
- current `outcomeMeta` snapshots for metadata and `sideSpecs`
- outcome-side fills from the indexed fill stream

You do not need to parse raw `replica_cmds` to use these HIP-4 query methods. Dwellir indexes the required L1 data and serves outcome market records directly. Use the [L1 gRPC Streaming API](https://www.dwellir.com/docs/hyperliquid/grpc) only when your application needs raw live block payloads.

---

## outcomeFills - HIP-4 Outcome Fill History

# outcomeFills - HIP-4 Outcome Fill History

Use `outcomeFills` for recent fills across all HIP-4 outcome coins, one `outcomeId`, or one encoded asset such as `#30`.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`outcomeFills` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `2,000` fills counts as `2,000` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be outcomeFills for /info REST requests. Omit this field for JSON-RPC.
- `coin` (`string, optional`): Exact outcome coin, such as
- `outcomeId` (`number, optional`): Outcome ID. When supplied without side, returns both Yes and No side fills.
- `side` (`string, optional`): Outcome side, one of yes, no, 0, or 1. Requires outcomeId.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "outcomeFills",
  "outcomeId": 3,
  "side": "yes",
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Billing counts one response/API credit per fill object returned.
- `user` (`string, required`): User address that produced the fill.
- `coin` (`string, required`): Outcome coin, for example
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block.

## Successful Response

```json
[
  {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "#30",
    "px": "0.72",
    "sz": "10",
    "side": "B",
    "time": 1772604210000,
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.001",
    "feeToken": "USDC",
    "txIndex": 7
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## outcomeFillsByTime - HIP-4 Outcome Fills by Time

# outcomeFillsByTime - HIP-4 Outcome Fills by Time

Use `outcomeFillsByTime` to scan HIP-4 outcome fills inside a bounded time window.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`outcomeFillsByTime` responses are billed by the number of fill objects returned, not as one response per HTTP request.
A response with `2,000` fills counts as `2,000` responses/API credits.

Requests that return an empty array are billed as `0` responses/API credits and do not count against usage. Error responses are not charged.

## Request Parameters

- `type` (`string, required`): Must be outcomeFillsByTime for /info REST requests. Omit this field for JSON-RPC.
- `coin` (`string, optional`): Exact outcome coin, such as
- `outcomeId` (`number, optional`): Outcome ID. When supplied without side, returns both Yes and No side fills.
- `side` (`string, optional`): Outcome side, one of yes, no, 0, or 1. Requires outcomeId.
- `startTime` (`number, optional`): Inclusive Unix timestamp in milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive Unix timestamp in milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_txIndex format. Resumes after that fill; startTime is skipped when cursor is supplied.
- `limit` (`number, optional`): Maximum rows to return, capped at 2000.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "outcomeFillsByTime",
  "coin": "#30",
  "startTime": 1772604000000,
  "endTime": 1772690400000,
  "limit": 100
}'
```

## Response Fields

- `fills` (`array, required`): Array of fill objects. /info returns this array directly; JSON-RPC returns it under result. Billing counts one response/API credit per fill object returned.
- `user` (`string, required`): User address that produced the fill.
- `coin` (`string, required`): Outcome coin, for example
- `px` (`string, required`): Execution price as a decimal string.
- `sz` (`string, required`): Fill size as a decimal string.
- `side` (`string, required`): B for bid/buy side, A for ask/sell side.
- `time` (`number, required`): Fill timestamp in Unix milliseconds.
- `txIndex` (`number, optional`): Block-local fill event index from node_fills_by_block. Use with time for cursor pagination.

## Successful Response

```json
[
  {
    "user": "0x1111111111111111111111111111111111111111",
    "coin": "#30",
    "px": "0.72",
    "sz": "10",
    "side": "B",
    "time": 1772604210000,
    "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",
    "oid": 121670079265,
    "crossed": true,
    "fee": "0.001",
    "feeToken": "USDC",
    "txIndex": 7
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`. Empty matches return `[]`; they are not errors.

---

## HIP-4 Outcome Metadata

# HIP-4 Outcome Metadata

Use `outcomeMeta` to read the latest active HIP-4 metadata snapshot, including outcome IDs, descriptions, `sideSpecs`, and prediction-market questions.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`outcomeMeta` is a single metadata response. It does not use the bundled-response `X-Iris-Billing-Weight` header.

## Request Parameters

- `type` (`string, required`): Must be outcomeMeta for /info REST requests. Omit this field for JSON-RPC.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{"type":"outcomeMeta"}'
```

## Response Fields

- `outcomes` (`array, required`): Active HIP-4 outcome metadata entries.
- `outcome` (`number, required`): Outcome ID assigned by HyperCore.
- `name` (`string, required`): Outcome name, for example Recurring.
- `description` (`string, required`): Pipe-delimited outcome specification.
- `sideSpecs` (`array, required`): Side definitions for the outcome.
- `questions` (`array, required`): One-off prediction-market question metadata when available.

## Successful Response

```json
{
  "outcomes": [
    {
      "outcome": 3,
      "name": "Recurring",
      "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
      "sideSpecs": [
        { "name": "Yes" },
        { "name": "No" }
      ]
    }
  ],
  "questions": []
}
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

`outcomeMeta` returns an object with `outcomes` and `questions`. Parse `description` defensively and drive labels from `sideSpecs` instead of hardcoding side names.

---

## registeredOutcomes - Active HIP-4 Outcomes

# registeredOutcomes - Active HIP-4 Outcomes

Use `registeredOutcomes` to list recent HIP-4 outcome registrations that have not settled yet.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`registeredOutcomes` responses are billed by the number of outcome objects returned. Empty arrays are billed as `0` responses/API credits.

## Request Parameters

- `type` (`string, required`): Must be registeredOutcomes for /info REST requests. Omit this field for JSON-RPC.
- `name` (`string, optional`): Optional exact outcome name filter.
- `class` (`string, optional`): Optional class filter, for example priceBinary.
- `underlying` (`string, optional`): Optional underlying asset filter, for example BTC.
- `period` (`string, optional`): Optional recurrence filter, for example 1d.
- `limit` (`number, optional`): Maximum rows to return, capped at 50.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "registeredOutcomes",
  "underlying": "BTC",
  "period": "1d",
  "limit": 10
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of active registered outcome objects. Billing counts one response/API credit per outcome object returned.
- `outcomeId` (`number, required`): Outcome ID.
- `yesAssetId` (`string, required`): Encoded Yes asset ID, for example
- `noAssetId` (`string, required`): Encoded No asset ID, for example
- `yesStats` (`object, required`): Fill-derived statistics for the Yes asset.
- `noStats` (`object, required`): Fill-derived statistics for the No asset.

## Successful Response

```json
[
  {
    "outcomeId": 3,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
    "class": "priceBinary",
    "underlying": "BTC",
    "expiry": "20260506-0600",
    "targetPrice": "80930",
    "period": "1d",
    "quoteToken": "150",
    "yesAssetId": "#30",
    "noAssetId": "#31",
    "yesStats": { "coin": "#30", "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0" },
    "noStats": { "coin": "#31", "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0" }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`.

---

## registeredOutcomesById - Active HIP-4 Outcomes by ID

# registeredOutcomesById - Active HIP-4 Outcomes by ID

Use `registeredOutcomesById` when you already know the outcome ID or encoded asset ID and need the registered outcome record.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`registeredOutcomesById` responses are billed by the number of outcome objects returned. Empty arrays are billed as `0` responses/API credits.

## Request Parameters

- `type` (`string, required`): Must be registeredOutcomesById for /info REST requests. Omit this field for JSON-RPC.
- `outcome_ids` (`array, optional`): Outcome IDs to fetch. Required unless asset_ids is supplied.
- `asset_ids` (`array, optional`): Outcome asset IDs such as

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "registeredOutcomesById",
  "outcome_ids": [3],
  "asset_ids": ["#30"]
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of registered outcome objects. Billing counts one response/API credit per outcome object returned.
- `outcomeId` (`number, required`): Outcome ID.
- `yesAssetId` (`string, required`): Encoded Yes asset ID, for example
- `noAssetId` (`string, required`): Encoded No asset ID, for example

## Successful Response

```json
[
  {
    "outcomeId": 3,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
    "class": "priceBinary",
    "underlying": "BTC",
    "expiry": "20260506-0600",
    "targetPrice": "80930",
    "period": "1d",
    "quoteToken": "150",
    "yesAssetId": "#30",
    "noAssetId": "#31"
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`.

---

## registeredOutcomesByTime - Active HIP-4 Outcomes by Time

# registeredOutcomesByTime - Active HIP-4 Outcomes by Time

Use `registeredOutcomesByTime` to backfill HIP-4 outcome registrations by registration event time.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`registeredOutcomesByTime` responses are billed by the number of outcome objects returned. Empty arrays are billed as `0` responses/API credits.

## Request Parameters

- `type` (`string, required`): Must be registeredOutcomesByTime for /info REST requests. Omit this field for JSON-RPC.
- `name` (`string, optional`): Optional exact outcome name filter.
- `class` (`string, optional`): Optional class filter, for example priceBinary.
- `underlying` (`string, optional`): Optional underlying asset filter, for example BTC.
- `period` (`string, optional`): Optional recurrence filter, for example 1d.
- `startTime` (`number, optional`): Inclusive registration timestamp in Unix milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive registration timestamp in Unix milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_outcomeId format.
- `limit` (`number, optional`): Maximum rows to return, capped at 50.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "registeredOutcomesByTime",
  "underlying": "BTC",
  "period": "1d",
  "startTime": 1772604000000,
  "endTime": 1772690400000,
  "limit": 50
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of registered outcome objects. Billing counts one response/API credit per outcome object returned.
- `outcomeId` (`number, required`): Outcome ID.
- `yesAssetId` (`string, required`): Encoded Yes asset ID, for example
- `noAssetId` (`string, required`): Encoded No asset ID, for example
- `yesStats` (`object, required`): Fill-derived statistics for the Yes asset.
- `noStats` (`object, required`): Fill-derived statistics for the No asset.

## Successful Response

```json
[
  {
    "outcomeId": 3,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
    "class": "priceBinary",
    "underlying": "BTC",
    "expiry": "20260506-0600",
    "targetPrice": "80930",
    "period": "1d",
    "quoteToken": "150",
    "yesAssetId": "#30",
    "noAssetId": "#31",
    "yesStats": { "coin": "#30", "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0" },
    "noStats": { "coin": "#31", "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0" }
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`.

---

## settledOutcomes - Settled HIP-4 Outcomes

# settledOutcomes - Settled HIP-4 Outcomes

Use `settledOutcomes` to list recent HIP-4 outcomes that have settled.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`settledOutcomes` responses are billed by the number of outcome objects returned. Empty arrays are billed as `0` responses/API credits.

## Request Parameters

- `type` (`string, required`): Must be settledOutcomes for /info REST requests. Omit this field for JSON-RPC.
- `name` (`string, optional`): Optional exact outcome name filter.
- `class` (`string, optional`): Optional class filter, for example priceBinary.
- `underlying` (`string, optional`): Optional underlying asset filter, for example BTC.
- `period` (`string, optional`): Optional recurrence filter, for example 1d.
- `limit` (`number, optional`): Maximum rows to return, capped at 50.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "settledOutcomes",
  "underlying": "BTC",
  "limit": 10
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of settled outcome objects. Billing counts one response/API credit per outcome object returned.
- `outcomeId` (`number, required`): Outcome ID.
- `settleFraction` (`string, optional`): Settlement fraction as a decimal string.
- `settlePrice` (`string, optional`): Settlement price as a decimal string.
- `yesAssetId` (`string, required`): Encoded Yes asset ID, for example
- `noAssetId` (`string, required`): Encoded No asset ID, for example

## Successful Response

```json
[
  {
    "outcomeId": 3,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
    "class": "priceBinary",
    "underlying": "BTC",
    "expiry": "20260506-0600",
    "targetPrice": "80930",
    "period": "1d",
    "quoteToken": "150",
    "yesAssetId": "#30",
    "noAssetId": "#31",
    "settleFraction": "1",
    "settlePrice": "83500"
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

Settled responses include registration metadata plus `settleFraction` and `settlePrice`. REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`.

---

## settledOutcomesById - Settled HIP-4 Outcomes by ID

# settledOutcomesById - Settled HIP-4 Outcomes by ID

Use `settledOutcomesById` when you already know the outcome ID or encoded asset ID and need the settlement record.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`settledOutcomesById` responses are billed by the number of outcome objects returned. Empty arrays are billed as `0` responses/API credits.

## Request Parameters

- `type` (`string, required`): Must be settledOutcomesById for /info REST requests. Omit this field for JSON-RPC.
- `outcome_ids` (`array, optional`): Outcome IDs to fetch. Required unless asset_ids is supplied.
- `asset_ids` (`array, optional`): Outcome asset IDs such as

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "settledOutcomesById",
  "outcome_ids": [3],
  "asset_ids": ["#30"]
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of settled outcome objects. Billing counts one response/API credit per outcome object returned.
- `outcomeId` (`number, required`): Outcome ID.
- `settleFraction` (`string, optional`): Settlement fraction as a decimal string.
- `settlePrice` (`string, optional`): Settlement price as a decimal string.
- `yesAssetId` (`string, required`): Encoded Yes asset ID, for example
- `noAssetId` (`string, required`): Encoded No asset ID, for example

## Successful Response

```json
[
  {
    "outcomeId": 3,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
    "class": "priceBinary",
    "underlying": "BTC",
    "expiry": "20260506-0600",
    "targetPrice": "80930",
    "period": "1d",
    "quoteToken": "150",
    "yesAssetId": "#30",
    "noAssetId": "#31",
    "settleFraction": "1",
    "settlePrice": "83500"
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

Settled responses include registration metadata plus `settleFraction` and `settlePrice`. REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`.

---

## settledOutcomesByTime - Settled HIP-4 Outcomes by Time

# settledOutcomesByTime - Settled HIP-4 Outcomes by Time

Use `settledOutcomesByTime` to backfill HIP-4 settlements by settlement event time.

## Endpoints

REST-style Info API:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info
```

JSON-RPC:

```text
POST https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/jsonrpc
```

## Billing

`settledOutcomesByTime` responses are billed by the number of outcome objects returned. Empty arrays are billed as `0` responses/API credits.

## Request Parameters

- `type` (`string, required`): Must be settledOutcomesByTime for /info REST requests. Omit this field for JSON-RPC.
- `name` (`string, optional`): Optional exact outcome name filter.
- `class` (`string, optional`): Optional class filter, for example priceBinary.
- `underlying` (`string, optional`): Optional underlying asset filter, for example BTC.
- `period` (`string, optional`): Optional recurrence filter, for example 1d.
- `startTime` (`number, optional`): Inclusive settlement timestamp in Unix milliseconds. Required unless cursor is supplied.
- `endTime` (`number, optional`): Exclusive settlement timestamp in Unix milliseconds.
- `cursor` (`string, optional`): Pagination cursor in time_outcomeId format.
- `limit` (`number, optional`): Maximum rows to return, capped at 50.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-index.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "settledOutcomesByTime",
  "underlying": "BTC",
  "startTime": 1772604000000,
  "endTime": 1772690400000,
  "limit": 50
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of settled outcome objects. Billing counts one response/API credit per outcome object returned.
- `outcomeId` (`number, required`): Outcome ID.
- `settleFraction` (`string, optional`): Settlement fraction as a decimal string.
- `settlePrice` (`string, optional`): Settlement price as a decimal string.
- `yesAssetId` (`string, required`): Encoded Yes asset ID, for example
- `noAssetId` (`string, required`): Encoded No asset ID, for example

## Successful Response

```json
[
  {
    "outcomeId": 3,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
    "class": "priceBinary",
    "underlying": "BTC",
    "expiry": "20260506-0600",
    "targetPrice": "80930",
    "period": "1d",
    "quoteToken": "150",
    "yesAssetId": "#30",
    "noAssetId": "#31",
    "settleFraction": "1",
    "settlePrice": "83500"
  }
]
```

## Error Responses

### Error

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid request"
  }
}
```

## Response

Settled responses include registration metadata plus `settleFraction` and `settlePrice`. REST `/info` responses return an array directly. JSON-RPC responses return the same array under `result`.

---

## HyperCore Info Endpoint

# HyperCore Info Endpoint

Dwellir's HyperCore Info Endpoint provides comprehensive access to Hyperliquid exchange data through a simple HTTP JSON API. Query market metadata, user account information, vault data, and exchange status with a single POST request.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## Key Benefits

### Higher Rate Limits

Unlike public Hyperliquid endpoints, Dwellir's HyperCore Info Endpoint provides significantly higher rate limits based on your subscription plan. This enables you to build production-grade applications without worrying about hitting rate limit restrictions.

**Rate limits scale with your plan:**

- Free tier: Standard public limits
- Growth tier: 10x higher limits
- Enterprise tier: Custom rate limits tailored to your needs

### Single Endpoint Architecture

All info endpoints are accessible through a single URL with different request types. This simplifies integration and reduces connection overhead.

**Base URL:** `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`

### Custom REST API Development

We're actively developing additional REST API endpoints for Hyperliquid. If you need custom endpoints or specialized data access patterns not covered by the standard Info Endpoint, [contact our team](https://dashboard.dwellir.com) to discuss your requirements.

## Available Endpoint Categories

### Market Metadata

Access trading pair information, leverage limits, and exchange status.

Use `meta`, `spotMeta`, and `perpDexs` to discover valid `market` symbols for [`candles`](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles#discovering-markets).

| Endpoint                                                              | Purpose                                                                      |
| --------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| [**meta**](https://www.dwellir.com/docs/hyperliquid/meta)                      | Get trading pair metadata including leverage limits                          |
| [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta)             | Get spot trading asset metadata                                              |
| [**outcomeMeta**](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta)       | Get HIP-4 outcome market metadata (recurring binaries, prediction questions) |
| [**exchangeStatus**](https://www.dwellir.com/docs/hyperliquid/exchange-status) | Monitor exchange health and status                                           |
| [**perpDexs**](https://www.dwellir.com/docs/hyperliquid/perp-dexs)             | Get all deployed perpetual DEXs with assets and configuration                |

### User Accounts

Query account states, positions, orders, and fee information.

| Endpoint                                                                                          | Purpose                                                                        |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state)                     | Get perpetual trading account state                                            |
| [**batchClearinghouseStates**](https://www.dwellir.com/docs/hyperliquid/batch-clearinghouse-states)        | Batch query account states for multiple users                                  |
| [**batchSpotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/batch-spot-clearinghouse-state) | Batch query spot balances for multiple users                                   |
| [**batchPortfolioState**](https://www.dwellir.com/docs/hyperliquid/batch-portfolio-state)                  | Batch query perp state, spot balances, and user abstraction for multiple users |
| [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state)                             | Get perp state, spot balances, and user abstraction in one request             |
| [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders)                                     | Retrieve all open orders for a user                                            |
| [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state)            | Get spot trading account balances                                              |
| [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees)                                         | Get user fee rates and volume data                                             |
| [**userAbstraction**](https://www.dwellir.com/docs/hyperliquid/user-abstraction)                           | Get account abstraction mode (unified, portfolio margin, etc.)                 |
| [**activeAssetData**](https://www.dwellir.com/docs/hyperliquid/active-asset-data)                          | Get leverage, max trade sizes, and available capital for a user and coin       |

### Vaults

Access vault performance data and user positions.

| Endpoint                                                                     | Purpose                         |
| ---------------------------------------------------------------------------- | ------------------------------- |
| [**leadingVaults**](https://www.dwellir.com/docs/hyperliquid/leading-vaults)          | Get top performing vaults       |
| [**vaultSummaries**](https://www.dwellir.com/docs/hyperliquid/vault-summaries)        | Get summary data for all vaults |
| [**userVaultEquities**](https://www.dwellir.com/docs/hyperliquid/user-vault-equities) | Get user's vault positions      |

### Validators

Query validator and delegation information.

| Endpoint                                                                   | Purpose                           |
| -------------------------------------------------------------------------- | --------------------------------- |
| [**validatorL1Votes**](https://www.dwellir.com/docs/hyperliquid/validator-l1-votes) | Get validator voting data         |
| [**delegatorSummary**](https://www.dwellir.com/docs/hyperliquid/delegator-summary)  | Get delegation summary for a user |

### Advanced Endpoints

Specialized endpoints for advanced use cases.

| Endpoint                                                                               | Purpose                              |
| -------------------------------------------------------------------------------------- | ------------------------------------ |
| [**userRateLimit**](https://www.dwellir.com/docs/hyperliquid/user-rate-limit)                   | Get rate limit information           |
| [**delegations**](https://www.dwellir.com/docs/hyperliquid/delegations)                         | Get staking delegation data          |
| [**subAccounts**](https://www.dwellir.com/docs/hyperliquid/sub-accounts)                        | Get sub-account information          |
| [**frontendOpenOrders**](https://www.dwellir.com/docs/hyperliquid/frontend-open-orders)         | Get orders formatted for UI display  |
| [**liquidatable**](https://www.dwellir.com/docs/hyperliquid/liquidatable)                       | Check liquidation status             |
| [**webData2**](https://www.dwellir.com/docs/hyperliquid/web-data-2)                             | Get comprehensive web interface data |
| [**extraAgents**](https://www.dwellir.com/docs/hyperliquid/extra-agents)                        | Get extra agent information          |
| [**userRole**](https://www.dwellir.com/docs/hyperliquid/user-role)                              | Get user role information            |
| [**userToMultiSigSigners**](https://www.dwellir.com/docs/hyperliquid/user-to-multi-sig-signers) | Get multi-sig signers and threshold  |
| [**maxBuilderFee**](https://www.dwellir.com/docs/hyperliquid/max-builder-fee)                   | Get maximum builder fee              |
| [**maxMarketOrderNtls**](https://www.dwellir.com/docs/hyperliquid/max-market-order-ntls)        | Get maximum market order notionals   |

## Quick Start

### Authentication

All requests use the shared info endpoint and include your Dwellir API key in the URL path:

```bash
curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info' \
  -H 'Content-Type: application/json' \
  -d '{"type":"meta"}'
```

### Request Format

All endpoints follow the same pattern:

```json
{
  "type": "ENDPOINT_TYPE",
  "param1": "value1",
  "param2": "value2"
}
```

### Example: Get Exchange Metadata

```bash
curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info' \
  -H 'Content-Type: application/json' \
  -d '{"type":"meta"}'
```

### Example: Get User Account State

```bash
curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "clearinghouseState",
    "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
  }'
```

## Error Handling

### HTTP Status Codes

| Code  | Description          | Solution                            |
| ----- | -------------------- | ----------------------------------- |
| `200` | Success              | Request completed successfully      |
| `400` | Bad Request          | Check request format and parameters |
| `401` | Unauthorized         | Verify API key is correct           |
| `422` | Unprocessable Entity | Check parameter values              |
| `429` | Rate Limit           | Implement backoff or upgrade plan   |
| `500` | Server Error         | Retry with exponential backoff      |

### Error Response Format

```json
{
  "error": "Error message description",
  "code": "ERROR_CODE"
}
```

## Best Practices

### 1. Implement Proper Error Handling

Always include retry logic with exponential backoff:

```javascript
async function queryEndpoint(payload, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(
        'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(payload)
        }
      );

      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      return await response.json();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
}
```

### 2. Cache Appropriately

Cache metadata endpoints to reduce API calls:

```javascript
// Cache meta data for 1 hour
const metaCache = new Map();
const META_TTL = 3600000; // 1 hour in ms

async function getMeta() {
  const cached = metaCache.get('meta');
  if (cached && Date.now() - cached.timestamp < META_TTL) {
    return cached.data;
  }

  const data = await queryEndpoint({ type: 'meta' });
  metaCache.set('meta', { data, timestamp: Date.now() });
  return data;
}
```

### 3. Monitor Rate Limits

Check response headers to track rate limit usage:

```javascript
const response = await fetch(url, options);
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');

if (parseInt(remaining) < 10) {
  console.warn('Approaching rate limit');
}
```

### 4. Use Timeouts

Set reasonable timeouts for all requests:

```javascript
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000); // 10s timeout

try {
  const response = await fetch(url, {
    ...options,
    signal: controller.signal
  });
  return await response.json();
} finally {
  clearTimeout(timeout);
}
```

## Code Examples

### Python

```python
import requests
from typing import Dict, Any

ENDPOINT = 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info'

def query_info_endpoint(endpoint_type: str, params: Dict[str, Any] = None) -> Dict:
    """Query the HyperCore Info Endpoint"""
    payload = {"type": endpoint_type}
    if params:
        payload.update(params)

    headers = {
        'Content-Type': 'application/json',
    }

    response = requests.post(ENDPOINT, json=payload, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json()

# Get metadata
meta = query_info_endpoint('meta')
print(f"Available pairs: {len(meta['universe'])}")

# Get user account state
user_state = query_info_endpoint(
    'clearinghouseState',
    {'user': '0x63E8c7C149556D5f34F833419A287bb9Ef81487f'}
)
print(f"Account value: {user_state['marginSummary']['accountValue']}")
```

### JavaScript/TypeScript

```typescript
const ENDPOINT = 'https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info';

interface InfoRequest {
  type: string;
  [key: string]: any;
}

async function queryInfoEndpoint<T>(request: InfoRequest): Promise<T> {
  const response = await fetch(ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request)
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }

  return await response.json();
}

// Get metadata
const meta = await queryInfoEndpoint({ type: 'meta' });
console.log(`Available pairs: ${meta.universe.length}`);

// Get user state
const userState = await queryInfoEndpoint({
  type: 'clearinghouseState',
  user: '0x63E8c7C149556D5f34F833419A287bb9Ef81487f'
});
console.log(`Account value: ${userState.marginSummary.accountValue}`);
```

## Support

Need help with the HyperCore Info Endpoint?

- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Email**: <support@dwellir.com>
- **Documentation**: [docs.dwellir.com](https://docs.dwellir.com)

For custom endpoint development or enterprise solutions, [contact our team](https://dashboard.dwellir.com).

***

*Access comprehensive Hyperliquid exchange data with Dwellir's enterprise-grade infrastructure. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## outcomeMeta - HyperCore Info Endpoint

# outcomeMeta - HyperCore Info Endpoint

Get metadata for HIP-4 outcome markets currently live on HyperCore, including each active outcome's ID, target price, expiry, side specifications, recurrence cadence, and any one-off prediction-market questions.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `outcomeMeta` endpoint is essential for any application that interacts with HIP-4 outcome markets:

- **Discover Live Outcomes** — Enumerate outcome IDs currently tradeable on HyperCore
- **Read the Strike & Expiry** — Surface the `targetPrice` and `expiry` to traders or pricing engines
- **Map `Yes` / `No` Sides** — Build UI affordances and routing for each side defined in `sideSpecs`
- **Handle Recurrence** — Detect when the prior recurring contract has rolled into the next period
- **Surface Prediction Questions** — Render any one-off `questions` released as named markets

## Request Parameters

- `type` (`string, required`): parameter: Must be `"outcomeMeta"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "outcomeMeta"
}'
```

## Response Fields

- `outcomes` (`array, required`): Array of currently live outcome contracts. Each entry describes one HIP-4 outcome market (recurring or one-off).
- `outcome` (`integer, required`): Outcome ID. Use this to reference the contract on HyperCore.
- `name` (`string, required`): Market label, e.g., `"Recurring"` for the daily BTC binary, or a question label for one-off markets.
- `description` (`string, required`): Pipe-delimited spec string: `class:<class>|underlying:<asset>|expiry:<YYYYMMDD-HHMM>|targetPrice:<price>|period:<period>`. `class` identifies the outcome type (e.g. `priceBinary`), `expiry` is UTC, `period` is the recurrence cadence (e.g. `1d`).
- `sideSpecs` (`array, required`): Array of side definitions. Binary outcomes return two entries — `"Yes"` and `"No"`.
- `sideSpecs[].name` (`string, required`): Side label. Each side is its own tradable instrument that settles to 1 if the side resolves true, otherwise 0.
- `questions` (`array, required`): Array of one-off prediction-market questions. Empty when only the recurring binary is live.

## Successful Response

```json
{
  "outcomes": [
    {
      "outcome": 3,
      "name": "Recurring",
      "description": "class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d",
      "sideSpecs": [
        {
          "name": "Yes"
        },
        {
          "name": "No"
        }
      ]
    }
  ],
  "questions": []
}
```

## Common Use Cases

### 1. Read the Live Recurring Binary

Pull the active BTC daily binary and surface its strike and expiry:

```javascript
async function getActiveBinary() {
  const meta = await getOutcomeMeta();

  const recurring = meta.outcomes.find(o => o.name === 'Recurring');
  if (!recurring) return null;

  const spec = Object.fromEntries(
    recurring.description.split('|').map(part => {
      const [key, ...rest] = part.split(':');
      return [key, rest.join(':')];
    })
  );

  return {
    outcomeId: recurring.outcome,
    underlying: spec.underlying,
    targetPrice: Number(spec.targetPrice),
    expiry: spec.expiry, // YYYYMMDD-HHMM UTC
    period: spec.period,
    sides: recurring.sideSpecs.map(s => s.name)
  };
}
```

### 2. Detect a Period Roll

Recurring outcomes refresh on a fixed cadence — the `outcome` ID changes each period. Cache the previous ID and detect rolls:

```javascript
let lastOutcomeId = null;

async function watchForRoll() {
  const meta = await getOutcomeMeta();
  const recurring = meta.outcomes.find(o => o.name === 'Recurring');
  if (!recurring) return;

  if (lastOutcomeId !== null && recurring.outcome !== lastOutcomeId) {
    console.log(`Period rolled: ${lastOutcomeId} -> ${recurring.outcome}`);
  }
  lastOutcomeId = recurring.outcome;
}
```

### 3. Render `Yes` / `No` Sides

Build the trade UI from `sideSpecs` rather than hardcoding labels — multi-outcome markets will return more than two sides:

```javascript
function renderSides(outcome) {
  return outcome.sideSpecs.map(side => ({
    label: side.name,
    instrumentKey: `${outcome.outcome}:${side.name}`
  }));
}
```

### 4. Surface One-Off Questions

When prediction-market questions roll out, they appear in the `questions` array alongside recurring outcomes:

```javascript
async function listAllMarkets() {
  const meta = await getOutcomeMeta();

  return [
    ...meta.outcomes.map(o => ({ kind: 'outcome', id: o.outcome, label: o.name })),
    ...meta.questions.map((q, idx) => ({ kind: 'question', id: idx, label: q.name ?? 'question' }))
  ];
}
```

## Best Practices

1. **Parse `description` defensively** — Treat unknown segments as opaque so future fields (additional `class` values, multi-leg specs) don't break your parser
2. **Don't hardcode `Yes` / `No`** — Drive UI from `sideSpecs` to stay forward-compatible with multi-outcome markets
3. **Refresh on schedule** — The recurring outcome ID changes each `period`; poll near the `expiry` time or after settlement
4. **Treat `questions` as additive** — The array is empty today but will populate as one-off prediction markets launch
5. **Use `expiry` in UTC** — `YYYYMMDD-HHMM` is always UTC; convert before display

## HIP-4 Context

[HIP-4](https://hyperliquid.gitbook.io/hyperliquid-docs/hyperliquid-improvement-proposals-hips/hip-4-outcome-markets) is the Hyperliquid Improvement Proposal that introduces outcome markets as a new HyperCore primitive. Outcomes are fully collateralized, dated contracts that settle to a value within a fixed range (typically `0` or `1`), giving HyperCore non-linear and prediction-market style payoffs without leverage or liquidation risk. Today the only outcome live on mainnet is the **recurring binary BTC outcome**, which settles every day at `06:00 UTC` against the BTC mark price on HyperCore. Multi-outcome and one-off markets are planned future phases.

The `outcomeMeta` endpoint is the canonical place to discover what is currently live: the outcome ID needed to trade or query positions, the underlying asset, the strike (`targetPrice`), the next `expiry`, and the available `sideSpecs` (typically `Yes` and `No`). Any outstanding one-off prediction-market questions appear in the `questions` array; for the current recurring-only deployment this is empty.

### Decoding the `description` String

Each outcome carries a pipe-delimited `description` string that fully specifies the contract:

```text
class:priceBinary|underlying:BTC|expiry:20260506-0600|targetPrice:80930|period:1d
```

| Segment       | Meaning                                                                                                                     |
| ------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `class`       | Outcome class. `priceBinary` means a binary payoff (`1` if `Yes` resolves true, otherwise `0`) based on a price comparison. |
| `underlying`  | Asset whose mark price the outcome settles against (e.g., `BTC`).                                                           |
| `expiry`      | Settlement time in `YYYYMMDD-HHMM` UTC. The recurring binary always uses `0600` UTC.                                        |
| `targetPrice` | Strike. `Yes` settles to `1` if the underlying mark price is above this at expiry; otherwise `No` settles to `1`.           |
| `period`      | Recurrence cadence. `1d` indicates a fresh contract is created daily once the previous one settles.                         |

## Related Endpoints

- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get perpetual market metadata
- [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta) — Get spot trading asset metadata
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Inspect a user's HyperCore positions, including outcome positions
- [**exchangeStatus**](https://www.dwellir.com/docs/hyperliquid/exchange-status) — Monitor exchange health before trading

## External References

- [HIP-4: Outcome markets](https://hyperliquid.gitbook.io/hyperliquid-docs/hyperliquid-improvement-proposals-hips/hip-4-outcome-markets) — Specification and rollout details

***

*Track HIP-4 outcome markets with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## HyperCore JSON-RPC API

# HyperCore JSON-RPC API

Dwellir provides a JSON-RPC 2.0 HTTP endpoint for querying HyperCore fill data. The API serves trade fill blocks with wire-level compatibility, so existing client code works unmodified.

## Endpoint

```
POST https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore
```

All requests use standard JSON-RPC 2.0 over HTTP with `Content-Type: application/json`.

This is the HyperCore JSON-RPC endpoint for Dwellir's indexed trade-fill
stream. It is separate from the HyperCore Info endpoint, which accepts
`{"type": "..."}` request bodies at
`https://api-hyperliquid-mainnet-info.n.dwellir.com/<API-KEY>/info`.

### Quick Test

```bash
curl -X POST 'https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/YOUR_API_KEY/hypercore' \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "hl_getLatestBlockNumber",
    "params": { "stream": "trades" },
    "id": 1
  }'
```

## Available Methods

| Method                                                                    | Description                                                   |
| ------------------------------------------------------------------------- | ------------------------------------------------------------- |
| [**hl\_getBatchBlocks**](https://www.dwellir.com/docs/hyperliquid/hl_getBatchBlocks)             | Return fill blocks in a `[from, to]` range for a given stream |
| [**hl\_getLatestBlockNumber**](https://www.dwellir.com/docs/hyperliquid/hl_getLatestBlockNumber) | Return the highest block number for a given stream            |

Only the methods above are implemented on this endpoint. Calls to
`hl_getBlockByNumber` return JSON-RPC `-32601` (`method not found`). To read
one recent block, call `hl_getBatchBlocks` with the same `from` and `to` block
number.

### hl\_getBatchBlocks

Retrieve a batch of fill blocks for a specified range. Each block contains trade events with timestamps and fill details.

**Ideal for:**

- Backfilling historical trade data
- Batch processing fill events
- Building trade analytics pipelines

[**View hl\_getBatchBlocks Documentation →**](https://www.dwellir.com/docs/hyperliquid/hl_getBatchBlocks)

### hl\_getLatestBlockNumber

Get the highest block number currently available for a stream. Use this to determine the current head before fetching batch blocks.

**Ideal for:**

- Discovering the latest available data
- Polling for new blocks
- Synchronization and catch-up logic

[**View hl\_getLatestBlockNumber Documentation →**](https://www.dwellir.com/docs/hyperliquid/hl_getLatestBlockNumber)

## Supported Streams

Currently only the `trades` stream is implemented. The upstream API also defines streams for orders, book updates, TWAP, events, and writer actions; these may be added in the future.

## Error Codes

Standard JSON-RPC 2.0 error codes are used:

| Code   | Meaning                                    |
| ------ | ------------------------------------------ |
| -32700 | Parse error                                |
| -32600 | Invalid request                            |
| -32601 | Method not found                           |
| -32602 | Invalid params                             |
| -32603 | Internal error                             |
| -32002 | Requested block range is not available yet |
| -32003 | Requested block range has been pruned      |

## Constraints

- **No batches** — Array-wrapped requests are rejected (`-32600`)
- **No notifications** — An `id` field (string or number) is required
- **Body limit** — 8 KiB max request body
- **Timeouts** — Each request gets a 30 s context deadline
- **Recent data only** — Use `hl_getLatestBlockNumber` first, then request a
  recent range slightly behind the head with `hl_getBatchBlocks`; older ranges
  can be pruned, and the newest block can briefly be unavailable to batch reads

***

*Query HyperCore fill data with Dwellir's JSON-RPC API. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## L2 Order Book - Aggregated Price Levels

# L2 Order Book - Aggregated Price Levels

Stream aggregated order book data showing total size at each price level. The L2 book provides a consolidated view of market depth, with configurable levels and price aggregation for bandwidth optimization.

Clone our complete examples: [github.com/dwellir-public/hyperliquid-orderbook-server-code-examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)

## How to Subscribe

Send a subscription message to the WebSocket endpoint:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC",
    "nSigFigs": 5,
    "nLevels": 20,
    "strict": true
  }
}
```

### Subscription Parameters

| Parameter  | Type   | Required | Default | Description                                                                   |
| ---------- | ------ | -------- | ------- | ----------------------------------------------------------------------------- |
| `type`     | string | Yes      | -       | Must be `"l2Book"`                                                            |
| `coin`     | string | Yes      | -       | Trading pair symbol (e.g., `"BTC"`, `"ETH"`, `"xyz:MSTR"`, `"@150"`, `"#10"`) |
| `nSigFigs` | number | No       | 5       | Price aggregation: 2-5 significant figures                                    |
| `nLevels`  | number | No       | 20      | Number of levels per side: 1-100                                              |
| `strict`   | bool   | No       | False   | Only send data on updates within the subscribed level interval                |

For best bid/offer in the public feed's payload shape, use the native [`bbo` subscription](https://www.dwellir.com/docs/hyperliquid/bbo) instead. It mirrors Hyperliquid's public `bbo` channel and is functionally equivalent to `l2Book` with `nLevels: 1, strict: true`. Stay on `l2Book(nLevels=1)` when you want rounded top-of-book via `nSigFigs`.

### Coin Format by Market Type

The `coin` field accepts different formats depending on the market:

| Market                           | Format         | Example                   | Notes                             |
| -------------------------------- | -------------- | ------------------------- | --------------------------------- |
| Standard perpetual               | Symbol         | `"BTC"`, `"ETH"`, `"SOL"` | No prefix needed                  |
| HIP-3 perpetual (permissionless) | `xyz:<symbol>` | `"xyz:MSTR"`              | Use full label with `xyz:` prefix |
| Spot                             | `@<index>`     | `"@150"`                  | Spot asset index                  |
| HIP-4 outcome                    | `#<encoding>`  | `"#10"`, `"#31"`          | Encoded outcome + side            |

#### Subscription Examples

Standard perpetual
HIP-3 perpetual
Spot
HIP-4 outcome

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "xyz:MSTR"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "@150"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "#31"
  }
}
```

For HIP-3 (permissionless perpetuals) markets, use the full coin label format with the `xyz:` prefix. For example, use `"xyz:MSTR"` for the MicroStrategy perpetual, not just `"MSTR"`. Standard perpetuals like BTC and ETH do not require a prefix.

For spot markets, use the `@{index}` format where the index is the spot asset index. For example, use `"@150"` for a specific spot market.

[HIP-4 outcome markets](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta) use the `#<encoding>` format. The encoding is derived from the outcome ID and binary side:

```
encoding = 10 * outcome + side
```

Only `side` `0` and `side` `1` are valid. For example, `"#10"` is outcome `1`, side `0`; `"#31"` is outcome `3`, side `1`. The same encoding maps to three representations:

- Outcome spot coin: `#<encoding>` (used here)
- Outcome token name: `+<encoding>`
- Outcome asset ID: `100_000_000 + encoding`

Live outcome IDs are returned by the [`outcomeMeta`](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta) info response.

### Understanding `nSigFigs` (Price Aggregation)

The `nSigFigs` parameter controls how prices are rounded for aggregation:

| nSigFigs | BTC Example | Effect                                  |
| -------- | ----------- | --------------------------------------- |
| 5        | $106,217    | Most granular - individual price points |
| 4        | $106,200    | Moderate aggregation                    |
| 3        | $106,000    | Coarse aggregation                      |
| 2        | $110,000    | Very coarse - major levels only         |

Lower `nSigFigs` values reduce message frequency and bandwidth but sacrifice price precision.

The first websocket message after subscribing is a `subscriptionResponse`; subsequent messages carry the `l2Book` payloads.

## Request Parameters

- `type` (`string, required`): Subscription parameter: Must be `"l2Book"`
- `coin` (`string, required`): Subscription parameter: Trading pair symbol. Standard perpetual: `"BTC"`. HIP-3 perpetual: `"xyz:MSTR"`. Spot: `"@150"`. HIP-4 outcome: `"#10"` (encoding = `10 * outcome + side`).
- `nSigFigs` (`number, optional`): Subscription parameter: Price aggregation: 2-5 significant figures
- `nLevels` (`number, optional`): Subscription parameter: Number of levels per side: 1-100
- `strict` (`bool, optional`): Subscription parameter: Only send data on updates within the subscribed level interval

## Request Example

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC",
    "nSigFigs": 5,
    "nLevels": 20,
    "strict": true
  }
}
```

## Response Fields

- `channel` (`string, required`): Always `"l2Book"` for this subscription type
- `data.coin` (`string, required`): Trading pair symbol
- `data.time` (`number, required`): Unix timestamp in milliseconds
- `data.levels` (`array, required`): Two-element array: `[bids, asks]`
- `levels[0]` (`array, required`): Bid levels (buyers), sorted best (highest) to worst
- `levels[1]` (`array, required`): Ask levels (sellers), sorted best (lowest) to worst

## Successful Response

```json
{
  "channel": "l2Book",
  "data": {
    "coin": "BTC",
    "time": 1767878802704,
    "levels": [
      [
        {"px": "90057", "sz": "5.34526", "n": 25},
        {"px": "90056", "sz": "0.01336", "n": 4},
        {"px": "90055", "sz": "0.33772", "n": 5},
        {"px": "90054", "sz": "0.01859", "n": 2},
        {"px": "90053", "sz": "0.08936", "n": 2}
      ],
      [
        {"px": "90058", "sz": "7.46316", "n": 18},
        {"px": "90059", "sz": "0.44694", "n": 5},
        {"px": "90060", "sz": "0.00013", "n": 1},
        {"px": "90061", "sz": "0.05576", "n": 3},
        {"px": "90062", "sz": "0.9716", "n": 3}
      ]
    ]
  }
}
```

## Response Field Reference

| Field         | Type   | Description                                         |
| ------------- | ------ | --------------------------------------------------- |
| `channel`     | string | Always `"l2Book"` for this subscription type        |
| `data.coin`   | string | Trading pair symbol                                 |
| `data.time`   | number | Unix timestamp in milliseconds                      |
| `data.levels` | array  | Two-element array: `[bids, asks]`                   |
| `levels[0]`   | array  | Bid levels (buyers), sorted best (highest) to worst |
| `levels[1]`   | array  | Ask levels (sellers), sorted best (lowest) to worst |

### Level Object Fields

| Field | Type   | Description                               |
| ----- | ------ | ----------------------------------------- |
| `px`  | string | Price level                               |
| `sz`  | string | Total size at this price level            |
| `n`   | number | Number of orders aggregated at this level |

## Use Cases

### Market Making

Monitor spread and depth to optimize quote placement:

- **Spread monitoring**: Track bid-ask spread for quote width
- **Inventory management**: Adjust quotes based on book imbalance
- **Competition analysis**: Count orders at each level to gauge competition

### Liquidity Analysis

Assess market depth for large order execution:

- **Slippage estimation**: Calculate expected price impact for order sizes
- **Best execution**: Find optimal order sizes and timing
- **Market quality metrics**: Track spread, depth, and resilience

### Support/Resistance Detection

Identify significant price levels from order concentration:

- **Order clusters**: Large `n` values indicate many orders at a level
- **Size walls**: High `sz` values suggest strong support/resistance
- **Level breaks**: Monitor when significant levels get absorbed

### Algorithmic Trading Signals

Generate trading signals from book dynamics:

- **Imbalance signals**: Buy when bids dominate, sell when asks dominate
- **Spread compression**: Trade when spread narrows (high liquidity)
- **Depth changes**: Alert on sudden liquidity additions or removals

## Subscription Management

### Adjusting Parameters

Change depth or aggregation by resubscribing:

```python
# Switch from 20 levels to 50 levels
await websocket.send(json.dumps({
    "method": "unsubscribe",
    "subscription": {"type": "l2Book", "coin": "BTC", "nLevels": 20}
}))

await websocket.send(json.dumps({
    "method": "subscribe",
    "subscription": {"type": "l2Book", "coin": "BTC", "nLevels": 50}
}))
```

### Bandwidth Optimization

For high-frequency updates, use lower `nSigFigs`:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC",
    "nSigFigs": 3,
    "nLevels": 10
  }
}
```

This reduces message size and frequency while maintaining key price levels.

## Get Access

Ready to integrate real-time Hyperliquid L2 order book data?

- **[Volume Calculator](https://www.dwellir.com/hyperliquid-orderbook#calculator)** - Estimate monthly message volume
- **[Contact Sales](mailto:support@dwellir.com)** - Get your WebSocket credentials
- **[Dashboard](https://dashboard.dwellir.com)** - Manage your subscription

***

*Stream institutional-grade Hyperliquid order book data with Dwellir's ultra-low latency infrastructure.*

---

## L4 Order Book - Individual Order Visibility

# L4 Order Book - Individual Order Visibility

The most detailed market data available - individual order visibility with user wallet addresses, order IDs, timestamps, and full order parameters. L4 data enables queue position tracking, whale watching, and advanced market microstructure analysis.

Clone our complete examples: [github.com/dwellir-public/hyperliquid-orderbook-server-code-examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)

## How to Subscribe

Send a subscription message to the WebSocket endpoint:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "BTC"
  }
}
```

### Subscription Parameters

| Parameter | Type   | Required | Description                                                                   |
| --------- | ------ | -------- | ----------------------------------------------------------------------------- |
| `type`    | string | Yes      | Must be `"l4Book"`                                                            |
| `coin`    | string | Yes      | Trading pair symbol (e.g., `"BTC"`, `"ETH"`, `"xyz:MSTR"`, `"@150"`, `"#10"`) |

### Coin Format by Market Type

The `coin` field accepts different formats depending on the market:

| Market                           | Format         | Example                   | Notes                             |
| -------------------------------- | -------------- | ------------------------- | --------------------------------- |
| Standard perpetual               | Symbol         | `"BTC"`, `"ETH"`, `"SOL"` | No prefix needed                  |
| HIP-3 perpetual (permissionless) | `xyz:<symbol>` | `"xyz:MSTR"`              | Use full label with `xyz:` prefix |
| Spot                             | `@<index>`     | `"@150"`                  | Spot asset index                  |
| HIP-4 outcome                    | `#<encoding>`  | `"#10"`, `"#31"`          | Encoded outcome + side            |

#### Subscription Examples

Standard perpetual
HIP-3 perpetual
Spot
HIP-4 outcome

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "BTC"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "xyz:MSTR"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "@150"
  }
}
```

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "#31"
  }
}
```

For HIP-3 (permissionless perpetuals) markets, use the full coin label format with the `xyz:` prefix. For example, use `"xyz:MSTR"` for the MicroStrategy perpetual, not just `"MSTR"`. Standard perpetuals like BTC and ETH do not require a prefix.

For spot markets, use the `@{index}` format where the index is the spot asset index. For example, use `"@150"` for a specific spot market.

[HIP-4 outcome markets](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta) use the `#<encoding>` format. The encoding is derived from the outcome ID and binary side:

```
encoding = 10 * outcome + side
```

Only `side` `0` and `side` `1` are valid. For example, `"#10"` is outcome `1`, side `0`; `"#31"` is outcome `3`, side `1`. The same encoding maps to three representations:

- Outcome spot coin: `#<encoding>` (used here)
- Outcome token name: `+<encoding>`
- Outcome asset ID: `100_000_000 + encoding`

Live outcome IDs are returned by the [`outcomeMeta`](https://www.dwellir.com/docs/hyperliquid/info-endpoint/outcome-meta) info response.

Unlike L2, L4 subscriptions do not support `nLevels` or `nSigFigs` - you receive the complete order book with all individual orders.

The first websocket message after subscribing is a `subscriptionResponse`; the next payload contains either a `Snapshot` or `Updates` wrapper.

## Message Types

L4 subscriptions produce two types of messages:

1. **Initial Snapshot** - Complete order book state when you subscribe
2. **Incremental Updates** - Changes as orders are placed, modified, or filled

### Initial Snapshot Response

When you first subscribe, you receive a complete snapshot of the order book wrapped in a `Snapshot` object:

```json
{
  "channel": "l4Book",
  "data": {
    "Snapshot": {
      "coin": "BTC",
      "height": 854890775,
      "levels": [
        [
          {
            "user": "0xf9109ada2f73c62e9889b45453065f0d99260a2d",
            "coin": "BTC",
            "side": "B",
            "limitPx": "90057",
            "sz": "0.33289",
            "oid": 289682065711,
            "timestamp": 1767878782721,
            "triggerCondition": "N/A",
            "isTrigger": false,
            "triggerPx": "0.0",
            "isPositionTpsl": false,
            "reduceOnly": false,
            "orderType": "Limit",
            "tif": "Alo",
            "cloid": "0x4c4617dbd8b94d358285c5c6d5a43df3"
          }
        ],
        [
          {
            "user": "0x13558be785661958932ceac35ba20de187275a42",
            "coin": "BTC",
            "side": "A",
            "limitPx": "90058",
            "sz": "0.37634",
            "oid": 289682176026,
            "timestamp": 1767878800615,
            "triggerCondition": "N/A",
            "isTrigger": false,
            "triggerPx": "0.0",
            "isPositionTpsl": false,
            "reduceOnly": false,
            "orderType": "Limit",
            "tif": "Alo",
            "cloid": "0x000000000814768000001999b6671c90"
          }
        ]
      ]
    }
  }
}
```

A full BTC order book snapshot can be large. The example above shows one order per side for brevity. Many WebSocket libraries default to a small message limit. If your connection closes immediately after subscribing, increase the maximum message size (for example, `max_size=50 * 1024 * 1024` in Python's `websockets` library).

### Incremental Update Response

After the initial snapshot, you receive incremental updates wrapped in an `Updates` object containing [`order_statuses`](#orderstatus-object-in-order_statuses-array) and [`book_diffs`](#bookdiff-object-in-book_diffs-array).

**Example 1: New Order**

This example shows a new order being added to the book:

```json
{
  "channel": "l4Book",
  "data": {
    "Updates": {
      "time": 1767878802703,
      "height": 854890776,
      "order_statuses": [
        {
          "time": "2026-01-08T13:26:42.703377851",
          "user": "0xbc927e87d072dfac3693846a83fa6922cc6c5f2a",
          "status": "open",
          "order": {
            "user": null,
            "coin": "BTC",
            "side": "B",
            "limitPx": "90056.0",
            "sz": "0.00014",
            "oid": 289682192129,
            "timestamp": 1767878802703,
            "triggerCondition": "N/A",
            "isTrigger": false,
            "triggerPx": "0.0",
            "isPositionTpsl": false,
            "reduceOnly": false,
            "orderType": "Limit",
            "tif": "Alo",
            "cloid": "0xa097c34ee13a42a1afeed2a5ce96b413"
          }
        }
      ],
      "book_diffs": [
        {
          "user": "0xbc927e87d072dfac3693846a83fa6922cc6c5f2a",
          "oid": 289682192129,
          "px": "90056.0",
          "coin": "BTC",
          "raw_book_diff": {
            "new": {
              "sz": "0.00014"
            }
          }
        }
      ]
    }
  }
}
```

**Example 2: Order Size Update (Partial Fill)**

This example shows an existing order being partially filled, with the size decreasing from 108.65 to 107.5:

```json
{
  "channel": "l4Book",
  "data": {
    "Updates": {
      "time": 1767878902834,
      "height": 854890880,
      "order_statuses": [],
      "book_diffs": [
        {
          "user": "0x97991003fd631e2923f40cab2a4fdc35e60dc807",
          "oid": 316542552323,
          "px": "84.371",
          "coin": "SOL",
          "raw_book_diff": {
            "update": {
              "origSz": "108.65",
              "newSz": "107.5"
            }
          }
        }
      ]
    }
  }
}
```

In this update:

- The order at price `84.371` was partially filled
- Original size (`origSz`): `108.65` SOL
- New remaining size (`newSz`): `107.5` SOL

## Response Field Reference

This section provides a detailed breakdown of all fields in L4 messages. For specific field values like order statuses, see [Order Status Values](#order-status-values).

All L4 messages follow this top-level structure:

```typescript
{
  channel: "l4Book",
  data: Snapshot | Updates
}
```

### Message Type 1: Snapshot (Initial State)

**Structure:** `{ channel: "l4Book", data: { Snapshot: {...} } }`

Received once when you first subscribe. Contains the complete order book state.

#### Snapshot Object

| Field    | Type                 | Description                                                                   |
| -------- | -------------------- | ----------------------------------------------------------------------------- |
| `coin`   | `string`             | Trading pair symbol (e.g., `"BTC"`, `"ETH"`, `"xyz:MSTR"`, `"@150"`)          |
| `height` | `number`             | Hyperliquid block height                                                      |
| `levels` | `[Order[], Order[]]` | Two-element array: `[bids, asks]`. Each element is an array of Order objects. |

#### Order Object (in `levels` arrays)

Each order in the `levels[0]` (bids) and `levels[1]` (asks) arrays contains:

| Field              | Type                      | Description                                                                                           |
| ------------------ | ------------------------- | ----------------------------------------------------------------------------------------------------- |
| `user`             | `string`                  | Wallet address of order owner (e.g., `"0xf9109ada..."`)                                               |
| `coin`             | `string`                  | Trading pair (e.g., `"BTC"`)                                                                          |
| `side`             | `"B" \| "A"`              | `"B"` = Bid (buy), `"A"` = Ask (sell)                                                                 |
| `limitPx`          | `string`                  | Limit price (e.g., `"90057"`)                                                                         |
| `sz`               | `string`                  | Remaining order size (e.g., `"0.33289"`)                                                              |
| `oid`              | `number`                  | Unique order ID (e.g., `289682065711`)                                                                |
| `timestamp`        | `number`                  | Order placement time in Unix milliseconds (e.g., `1767878782721`)                                     |
| `triggerCondition` | `string`                  | Trigger condition type, or `"N/A"` if not a trigger order                                             |
| `isTrigger`        | `boolean`                 | Whether this is a trigger/stop order                                                                  |
| `triggerPx`        | `string`                  | Trigger price, or `"0.0"` if not a trigger order                                                      |
| `isPositionTpsl`   | `boolean`                 | Whether this is a position take-profit/stop-loss order                                                |
| `reduceOnly`       | `boolean`                 | Whether order can only reduce position                                                                |
| `orderType`        | `string`                  | Order type: `"Limit"`, `"Market"`, `"Stop Market"`, `"Stop Limit"`, `"Scale"`, `"TWAP"`               |
| `tif`              | `"Gtc" \| "Ioc" \| "Alo"` | Time-in-force: `"Gtc"` (Good til Cancel), `"Ioc"` (Immediate or Cancel), `"Alo"` (Add Liquidity Only) |
| `cloid`            | `string`                  | Client order ID - hex string provided by user (e.g., `"0x4c4617dbd8b94d35..."`)                       |

### Message Type 2: Updates (Incremental Changes)

**Structure:** `{ channel: "l4Book", data: { Updates: {...} } }`

Received continuously after the snapshot. Contains incremental changes to the order book.

#### Updates Object

| Field            | Type            | Description                                                                                                                                                                                       |
| ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `time`           | `number`        | Unix timestamp in milliseconds (e.g., `1767878802703`)                                                                                                                                            |
| `height`         | `number`        | Hyperliquid block height - increments with each update                                                                                                                                            |
| `order_statuses` | `OrderStatus[]` | Array of [order status changes](#orderstatus-object-in-order_statuses-array) (new orders, fills, cancellations, rejections). See [Order Status Values](#order-status-values) for status meanings. |
| `book_diffs`     | `BookDiff[]`    | Array of [order book modifications](#bookdiff-object-in-book_diffs-array) (additions, removals, size changes)                                                                                     |

The `order_statuses` array contains **status transitions** (open, filled, canceled), not per-fill execution data. To get individual fill details (price, size, counterparty), subscribe to the [Trades stream](https://www.dwellir.com/docs/hyperliquid/trades) and correlate using `oid`. See [Understanding Order Data Flow](#understanding-order-data-flow) for details.

#### OrderStatus Object (in `order_statuses` array)

| Field    | Type     | Description                                                                                                                                                              |
| -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `time`   | `string` | ISO-8601 timestamp with nanosecond precision (e.g., `"2026-01-08T13:26:42.703377851"`)                                                                                   |
| `user`   | `string` | Wallet address of order owner                                                                                                                                            |
| `status` | `string` | Order status: `"open"`, `"filled"`, `"canceled"`, `"badAloPxRejected"`, etc. See [Order Status Values](#order-status-values) for all possible values and their meanings. |
| `order`  | `Order`  | Order object with same structure as [Order Object](#order-object-in-levels-arrays) above (but `user` field may be `null`)                                                |

#### BookDiff Object (in `book_diffs` array)

The `book_diffs` array contains changes to individual orders in the book. Each diff describes what happened to a specific order - whether it was added (`new`), partially filled (`update`), modified (`modified`), or removed (`remove`).

**Common fields present in all diff types:**

| Field           | Type                                                | Description                                                                                                                                                                                                                                                                                                  |
| --------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `user`          | `string`                                            | Wallet address of order owner (e.g., `"0xbc927e87..."`)                                                                                                                                                                                                                                                      |
| `oid`           | `number`                                            | Unique order ID being modified (e.g., `289682192129`)                                                                                                                                                                                                                                                        |
| `px`            | `string`                                            | Price level where order exists/existed (e.g., `"90056.0"`)                                                                                                                                                                                                                                                   |
| `coin`          | `string`                                            | Trading pair (e.g., `"BTC"`)                                                                                                                                                                                                                                                                                 |
| `raw_book_diff` | `NewDiff \| UpdateDiff \| ModifiedDiff \| "remove"` | Describes what changed. Can be: `{ new: { sz } }` for new orders, `{ update: { origSz, newSz } }` for partial fills, `{ modified: { sz } }` for amendments, or `"remove"` for cancellations/complete fills. See [BookDiff Types](#bookdiff-types-the-raw_book_diff-field) below for detailed specifications. |

### BookDiff Types (the `raw_book_diff` field)

The `raw_book_diff` field indicates what happened to an order. It can take four forms:

| Type             | TypeScript Definition                           | Description                                                                                                                                                                                                                                                                          |
| ---------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **NewDiff**      | `{ new: { sz: string } }`                       | New order added to the book. The `sz` field contains the order size. Reference the corresponding entry in [`order_statuses`](#orderstatus-object-in-order_statuses-array) with matching `oid` to get full order details (side, tif, etc.).                                           |
| **RemoveDiff**   | `"remove"`                                      | Order completely removed from book. Can occur due to: full fill (check [`order_statuses`](#orderstatus-object-in-order_statuses-array) for [`filled`](#successful-states) status), user cancellation ([`canceled`](#cancellation-states)), system cancellation, or order expiration. |
| **UpdateDiff**   | `{ update: { origSz: string, newSz: string } }` | Order size changed (usually decreased due to partial fill). Contains both the original size (`origSz`) and the new remaining size (`newSz`).                                                                                                                                         |
| **ModifiedDiff** | `{ modified: { sz: string } }`                  | Order size modified (typically from order amendments). The `sz` field contains the new remaining size. Unlike `UpdateDiff`, this only provides the new size without the original.                                                                                                    |

### Order Status Values

The `status` field in `order_statuses` indicates the result of order processing. Understanding these statuses is critical for debugging order placement issues.

| Status                                      | Type         | Description                                                               | Debugging Notes                                                                                                                                                                                                                                                                                                         |
| ------------------------------------------- | ------------ | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `open`                                      | Success      | Order successfully placed and resting on the book                         | Most common successful status. Order is live and can be filled.                                                                                                                                                                                                                                                         |
| `filled`                                    | Success      | Order fully executed                                                      | Order matched completely. Check `book_diffs` for removal. **Note:** the `sz` field in the order object may be non-zero even for `filled` status. This reflects remaining size at the time the status was emitted by the Hyperliquid node, not necessarily the final state. Use `book_diffs` for accurate size tracking. |
| `triggered`                                 | Success      | Trigger/stop order activated                                              | Conditional order has been triggered and converted to regular order.                                                                                                                                                                                                                                                    |
| `canceled`                                  | Cancellation | Order canceled by user or system                                          | Standard cancellation. Check if user-initiated or system-triggered.                                                                                                                                                                                                                                                     |
| `reduceOnlyCanceled`                        | Cancellation | Reduce-only order was canceled                                            | Position closed or order would have increased position instead of reducing.                                                                                                                                                                                                                                             |
| `selfTradeCanceled`                         | Cancellation | Order canceled to prevent self-trading                                    | Same user's buy and sell orders would have matched. Exchange prevented self-execution.                                                                                                                                                                                                                                  |
| `marginCanceled`                            | Cancellation | Order canceled due to insufficient margin                                 | User's margin balance insufficient to maintain the order.                                                                                                                                                                                                                                                               |
| `openInterestCapCanceled`                   | Cancellation | Order canceled due to open interest cap reached                           | Market has reached maximum open interest limit. Try again later or use different market.                                                                                                                                                                                                                                |
| `scheduledCancel`                           | Cancellation | Order canceled on a scheduled basis                                       | Order was automatically canceled based on time or condition schedule.                                                                                                                                                                                                                                                   |
| `siblingFilledCanceled`                     | Cancellation | Order canceled because sibling order filled                               | Paired/bracket order canceled when the primary order executed. Common with OCO (One-Cancels-Other) orders.                                                                                                                                                                                                              |
| `badAloPxRejected`                          | Rejection    | Add-liquidity-only order rejected (never reached book)                    | **Most common rejection** (\~70% in production data). ALO order would have crossed spread and executed as taker. Price was too aggressive for maker-only order.                                                                                                                                                         |
| `iocCancelRejected`                         | Rejection    | Immediate-or-cancel order rejected (never reached book)                   | IOC order couldn't fill immediately at specified price. No matching liquidity available.                                                                                                                                                                                                                                |
| `perpMarginRejected`                        | Rejection    | Perpetual futures order rejected (never reached book)                     | Insufficient margin to open the position. Check account balance and leverage.                                                                                                                                                                                                                                           |
| `perpMaxPositionRejected`                   | Rejection    | Perpetual order rejected - exceeds max position size (never reached book) | Order would exceed maximum allowed position size for this market. Reduce order size or close existing positions.                                                                                                                                                                                                        |
| `minTradeNtlRejected`                       | Rejection    | Minimum notional value rejected (never reached book)                      | Order size (price × quantity) below exchange minimum. Increase order size.                                                                                                                                                                                                                                              |
| `reduceOnlyRejected`                        | Rejection    | Reduce-only order rejected (never reached book)                           | Order marked reduce-only but would have increased position or no position exists to reduce.                                                                                                                                                                                                                             |
| `insufficientSpotBalanceRejected`           | Rejection    | Insufficient spot token balance (never reached book)                      | Not enough spot token balance to place order. Deposit more tokens or reduce order size.                                                                                                                                                                                                                                 |
| `oracleRejected`                            | Rejection    | Order rejected due to oracle price issues (never reached book)            | Oracle price feed unavailable or stale. Wait for oracle to update or check market status.                                                                                                                                                                                                                               |
| `positionFlipAtOpenInterestCapRejected`     | Rejection    | Position flip rejected at open interest cap (never reached book)          | Order would flip position direction when market is at OI cap. Close existing position first.                                                                                                                                                                                                                            |
| `positionIncreaseAtOpenInterestCapRejected` | Rejection    | Position increase rejected at open interest cap (never reached book)      | Cannot increase position size when market has reached open interest limit.                                                                                                                                                                                                                                              |
| `tooAggressiveAtOpenInterestCapRejected`    | Rejection    | Order too aggressive at open interest cap (never reached book)            | Order price too aggressive when market near OI cap. Use less aggressive limit price.                                                                                                                                                                                                                                    |

## Understanding Order Data Flow

Hyperliquid separates order data across two channels. Understanding this separation is essential for building correct trading systems.

| Data                                                   | Channel                                                  | What you get                                                     |
| ------------------------------------------------------ | -------------------------------------------------------- | ---------------------------------------------------------------- |
| Order status transitions (open, filled, canceled)      | **L4 Book**                                              | When an order changes state, not how it was filled               |
| Book mutations (new, update, remove)                   | **L4 Book**                                              | Size changes at each price level per order                       |
| Individual fill executions (price, size, counterparty) | **[Trades](https://www.dwellir.com/docs/hyperliquid/trades)** | Each execution with price, size, hash, and both wallet addresses |

**For complete order visibility, subscribe to both channels** and correlate events using the `oid` (order ID) field:

```python
# Subscribe to both channels for full order tracking
await websocket.send(json.dumps({
    "method": "subscribe",
    "subscription": {"type": "l4Book", "coin": "ETH"}
}))
await websocket.send(json.dumps({
    "method": "subscribe",
    "subscription": {"type": "trades", "coin": "ETH"}
}))

# Correlate: l4Book order_statuses use "oid" in the order object,
# trades use "tid" (trade ID) but can be matched to orders by
# tracking which orders are open at each block height.
```

### Why "only 2 events" is normal

A common question is why an order shows only `open` then `filled` with no events in between. This is expected behavior. The L4 Book `order_statuses` array reports **state transitions**, not individual fills.

If an order receives 5 partial fills before completing, the L4 Book reports:

1. `open` - order placed on the book
2. `filled` - order fully executed

The 5 individual fills appear on the **Trades** stream, not in `order_statuses`. The `book_diffs` array tracks the size decreases from partial fills as `update` diffs.

## Order Lifecycle Patterns

Based on production data for ETH, these are the most common order lifecycle patterns on the L4 Book channel:

| Pattern                               | Frequency              | Description                                                                                         |
| ------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------- |
| Single rejection event                | \~88% of all orders    | Orders rejected immediately (`badAloPxRejected`, `perpMarginRejected`, etc.). Never reach the book. |
| `open` then `canceled`                | \~98.9% of multi-event | Order placed and later canceled by the user or system                                               |
| `open` then `filled`                  | \~1.1% of multi-event  | Order placed and fully executed (may happen in the same block)                                      |
| `triggered` then `filled`             | Rare                   | Stop/trigger order activated and then filled                                                        |
| `open` then `triggered` then `filled` | Very rare              | Order transitions through triggered state before filling                                            |

Most orders on Hyperliquid are **ALO (Add Liquidity Only)** orders from market makers that get rejected because the price crossed the spread. This is normal high-frequency trading behavior.

## Request Parameters

- `type` (`string, required`): Subscription parameter: Must be `"l4Book"`
- `coin` (`string, required`): Subscription parameter: Trading pair symbol. Standard perpetual: `"BTC"`. HIP-3 perpetual: `"xyz:MSTR"`. Spot: `"@150"`. HIP-4 outcome: `"#10"` (encoding = `10 * outcome + side`).

## Request Example

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "BTC"
  }
}
```

## Response Fields

- `channel` (`string, required`): Always `"l4Book"` for this subscription type
- `data.Snapshot` (`object, optional`): Initial full book snapshot after subscribing
- `data.Updates` (`object, optional`): Incremental order book changes after the snapshot

## Successful Response

```json
{
  "channel": "l4Book",
  "data": {
    "Snapshot": {
      "coin": "BTC",
      "height": 927625914,
      "levels": [[], []]
    }
  }
}
```

## Use Cases

### Queue Position Optimization

Understand your place in the order queue:

- **Time priority**: See exactly where your order sits at a price level
- **Fill probability**: Estimate likelihood of execution based on orders ahead
- **Repositioning**: Decide when to cancel and replace for better position

### Whale Wallet Tracking

Monitor large or notable traders:

- **Address tracking**: Follow specific wallet addresses
- **Size alerts**: Trigger on orders above threshold
- **Pattern detection**: Identify accumulation or distribution

### Market Microstructure Research

Analyze order flow dynamics:

- **Order arrival rates**: Study how orders enter the book
- **Cancellation patterns**: Track order lifetime and modification frequency
- **Toxicity analysis**: Measure adverse selection from order flow

### Smart Order Routing

Optimize order execution strategy:

- **Liquidity mapping**: Know exactly what size exists at each level
- **Hidden liquidity**: Detect when large orders are being worked
- **Impact estimation**: Model expected slippage from current book state

## Bandwidth Considerations

L4 data is significantly higher bandwidth than L2:

| Aspect               | L2                    | L4                     |
| -------------------- | --------------------- | ---------------------- |
| Data per level       | 3 fields (px, sz, n)  | 15+ fields per order   |
| Orders visible       | Aggregated count only | Every individual order |
| Update frequency     | Per price level       | Per order change       |
| Typical message size | 1-5 KB                | 10-100+ KB             |

Consider subscribing to L4 only for coins where you need individual order visibility.

## Get Access

Ready to integrate real-time Hyperliquid L4 order book data?

- **[Volume Calculator](https://www.dwellir.com/hyperliquid-orderbook#calculator)** - Estimate monthly message volume
- **[Contact Sales](mailto:support@dwellir.com)** - Get your WebSocket credentials
- **[Dashboard](https://dashboard.dwellir.com)** - Manage your subscription

***

*Stream institutional-grade Hyperliquid order book data with Dwellir's ultra-low latency infrastructure.*

---

## leadingVaults - HyperCore Info Endpoint

# leadingVaults - HyperCore Info Endpoint

Get information about top vaults and vault ranking metrics from Hyperliquid.

The Dwellir Hyperliquid Info API currently returns
`Failed to deserialize the JSON body into the target type` for
`leadingVaults` requests.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

`leadingVaults` is listed in Hyperliquid public docs, but Dwellir currently returns a deserialization error on this Info endpoint. Use a Dwellir-compatible alternative for
vault data until this method is restored.

## Endpoint Status

At this time, Dwellir does not return a stable `leadingVaults` payload for this endpoint.

If you are building vault discovery features, use supported data sources in your integration architecture and
consider contacting
<support@dwellir.com> for availability updates.

## Request Parameters

- `type` (`string, required`): parameter: Must be `"leadingVaults"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "leadingVaults"
}'
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
"Failed to deserialize the JSON body into the target type"
```

## Error Responses

### Error Response

- Code: `422`
- Description: The request payload cannot be deserialized for this method on the Dwellir Hyperliquid Info API.

```json
"Failed to deserialize the JSON body into the target type"
```

## Related Endpoints

- [**vaultSummaries**](https://www.dwellir.com/docs/hyperliquid/vault-summaries) — Get summary information for all vaults
- [**userVaultEquities**](https://www.dwellir.com/docs/hyperliquid/user-vault-equities) — Get a user's vault positions
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get user account state

***

*Access Hyperliquid vault metrics with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## liquidatable - HyperCore Info Endpoint

# liquidatable - HyperCore Info Endpoint

Check if a user's positions are at risk of liquidation, providing critical risk management information.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `liquidatable` endpoint is essential for:

- **Risk Monitoring** — Check liquidation risk for positions
- **Margin Management** — Monitor account health and safety
- **Liquidation Alerts** — Build alert systems for position risk
- **Portfolio Safety** — Ensure positions are within safe margins

## Request Parameters

- `type` (`string, required`): parameter: Must be `"liquidatable"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "liquidatable",
  "user": "0x420a4ed7b6bb361da586868adec2f2bb9ab75e66"
}'
```

## Response Fields

- `liquidatable` (`boolean, required`): Whether the user's positions are currently liquidatable

## Successful Response

```json
{
  "liquidatable": false
}
```

## Common Use Cases

### 1. Liquidation Risk Monitor

Monitor liquidation risk continuously:

```javascript
async function monitorLiquidationRisk(userAddress) {
  const status = await checkLiquidatable(userAddress);

  console.log('=== Liquidation Risk Monitor ===\n');

  if (status.liquidatable) {
    console.error('⚠️  CRITICAL: Positions are liquidatable!');
    console.error('Action required: Add margin or reduce position size');
  } else {
    console.log('✓ Positions are safe from liquidation');
  }

  return status.liquidatable;
}

// Usage
const atRisk = await monitorLiquidationRisk('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
```

### 2. Build Liquidation Alert System

Create automated liquidation alerts:

```javascript
class LiquidationAlertSystem {
  constructor(userAddress, checkIntervalMs = 30000) {
    this.userAddress = userAddress;
    this.checkIntervalMs = checkIntervalMs;
    this.wasLiquidatable = false;
  }

  async start(onAlert) {
    while (true) {
      try {
        const status = await checkLiquidatable(this.userAddress);

        if (status.liquidatable && !this.wasLiquidatable) {
          // Just became liquidatable - send alert
          onAlert({
            severity: 'critical',
            message: 'Positions now liquidatable!',
            timestamp: new Date().toISOString()
          });
        } else if (!status.liquidatable && this.wasLiquidatable) {
          // No longer liquidatable - send recovery alert
          onAlert({
            severity: 'info',
            message: 'Positions no longer liquidatable',
            timestamp: new Date().toISOString()
          });
        }

        this.wasLiquidatable = status.liquidatable;
      } catch (error) {
        console.error('Alert system error:', error);
      }

      await new Promise(r => setTimeout(r, this.checkIntervalMs));
    }
  }
}

// Usage
const alertSystem = new LiquidationAlertSystem('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
alertSystem.start((alert) => {
  console.log(`[${alert.severity.toUpperCase()}] ${alert.message}`);
  // Send notification via email, SMS, etc.
});
```

### 3. Risk Dashboard

Create a risk management dashboard:

```javascript
async function getRiskDashboard(userAddress) {
  try {
    const status = await checkLiquidatable(userAddress);

    return {
      status: 'success',
      liquidationRisk: status.liquidatable ? 'HIGH' : 'LOW',
      isLiquidatable: status.liquidatable,
      recommendation: status.liquidatable
        ? 'Immediate action required: Add margin or close positions'
        : 'Positions are within safe margins',
      lastChecked: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message
    };
  }
}

// Usage
const dashboard = await getRiskDashboard('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
console.log('Risk Dashboard:', dashboard);
```

### 4. Pre-Trade Risk Check

Check liquidation risk before opening new positions:

```javascript
async function preTradeRiskCheck(userAddress) {
  const status = await checkLiquidatable(userAddress);

  if (status.liquidatable) {
    return {
      canTrade: false,
      reason: 'Existing positions are liquidatable',
      recommendation: 'Resolve liquidation risk before opening new positions'
    };
  }

  return {
    canTrade: true,
    reason: 'Account health is good',
    recommendation: 'Safe to proceed with new trades'
  };
}

// Usage
const riskCheck = await preTradeRiskCheck('0x420a4ed7b6bb361da586868adec2f2bb9ab75e66');
if (riskCheck.canTrade) {
  console.log('✓ Safe to open new positions');
} else {
  console.error(`✗ Cannot trade: ${riskCheck.reason}`);
}
```

### 5. Continuous Risk Monitoring

Monitor risk with logging:

```javascript
async function continuousRiskMonitoring(userAddress, logInterval = 60000) {
  const riskLog = [];

  const monitor = async () => {
    const status = await checkLiquidatable(userAddress);

    const logEntry = {
      timestamp: new Date().toISOString(),
      liquidatable: status.liquidatable,
      riskLevel: status.liquidatable ? 'CRITICAL' : 'SAFE'
    };

    riskLog.push(logEntry);
    console.log(`[${logEntry.timestamp}] Risk: ${logEntry.riskLevel}`);

    if (status.liquidatable) {
      console.error('⚠️  ALERT: Liquidation risk detected!');
    }
  };

  // Run immediately and then at intervals
  await monitor();
  setInterval(monitor, logInterval);

  return riskLog;
}

// Usage
const riskLog = await continuousRiskMonitoring(
  '0x420a4ed7b6bb361da586868adec2f2bb9ab75e66',
  60000 // Check every minute
);
```

## Best Practices

1. **Check frequently** — Monitor every 30-60 seconds for active positions
2. **Set up alerts** — Implement immediate notifications for liquidation risk
3. **Act quickly** — Respond immediately when positions become liquidatable
4. **Combine with margin data** — Use with clearinghouseState for full context
5. **Log history** — Track risk over time for pattern analysis

## Performance Considerations

### Efficient Risk Monitoring

```javascript
class EfficientRiskMonitor {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.cache = null;
    this.cacheTime = 0;
    this.cacheDuration = 10000; // 10 seconds
  }

  async check(forceRefresh = false) {
    const now = Date.now();

    if (!forceRefresh && this.cache && (now - this.cacheTime) < this.cacheDuration) {
      return this.cache;
    }

    const status = await checkLiquidatable(this.userAddress);
    this.cache = status;
    this.cacheTime = now;

    return status;
  }
}
```

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get detailed margin and position data
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — View orders that may affect liquidation risk
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Understand fee impact on margin
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get liquidation price calculations

***

*Protect your positions with real-time liquidation monitoring via Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## ListFeeds - Discover V3 Raw Feeds

# ListFeeds - Discover V3 Raw Feeds

`ListFeeds` returns the V3 raw feeds available on the selected endpoint. Call it during startup or capability refresh instead of assuming that every declared raw RPC is available.

## Method signature

```protobuf
rpc ListFeeds(ListFeedsRequest) returns (ListFeedsResponse) {}
```

The authenticated request has no parameters:

```bash
grpcurl -format json \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/ListFeeds
```

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
grpcurl -format json \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/ListFeeds
```

## Response Fields

- `feeds` (`FeedInfo[], required`): Raw feeds available on this endpoint.
- `feeds.id` (`string, required`): Stable feed identifier.
- `feeds.source` (`string, required`): Stable source identifier for the feed.
- `feeds.position_kinds` (`PositionKind[], required`): Cursor kinds accepted by this feed.
- `feeds.filter_fields` (`string[], required`): Valid FieldFilter names; empty means filtering is not supported.
- `feeds.progress` (`ProgressSupport, optional`): Default, minimum, and maximum progress-frame interval in milliseconds; unset means the feed does not support progress frames.

## Successful Response

```protobuf
feeds: {
  id: "blocks"
  source: "replica_cmds"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "fills"
  source: "node_fills_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "mempool-txs"
  source: "mempool_txs"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_TIMESTAMP_NS
}
feeds: {
  id: "misc-events"
  source: "misc_events_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "order-statuses"
  source: "node_order_statuses_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "raw-book-diffs"
  source: "node_raw_book_diffs_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "twap-statuses"
  source: "node_twap_statuses_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
```

## Error Responses

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call the service.

## Current feed inventory

An endpoint that serves every raw feed lists these seven:

```protobuf
feeds: {
  id: "blocks"
  source: "replica_cmds"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "fills"
  source: "node_fills_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "mempool-txs"
  source: "mempool_txs"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_TIMESTAMP_NS
}
feeds: {
  id: "misc-events"
  source: "misc_events_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "order-statuses"
  source: "node_order_statuses_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "raw-book-diffs"
  source: "node_raw_book_diffs_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
feeds: {
  id: "twap-statuses"
  source: "node_twap_statuses_by_block"
  position_kinds: POSITION_KIND_TIMESTAMP
  position_kinds: POSITION_KIND_BLOCK_NUMBER
  filter_fields: "users"
  filter_fields: "coins"
  progress: {
    default_interval_ms: 20000
    min_interval_ms: 10000
    max_interval_ms: 60000
  }
}
```

Registries can vary by endpoint, and the mempool feed is not served everywhere. Call `ListFeeds` at runtime and refresh the inventory after changing endpoints.

## Response fields

| Field                    | Meaning                                                                                                                                                                                                          |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `feeds[].id`             | Stable feed identifier used by the gateway                                                                                                                                                                       |
| `feeds[].source`         | Stable source identifier for the feed                                                                                                                                                                            |
| `feeds[].position_kinds` | Cursor kinds accepted by that feed. `mempool-txs` accepts `POSITION_KIND_TIMESTAMP` and `POSITION_KIND_TIMESTAMP_NS`; the block-envelope feeds accept `POSITION_KIND_TIMESTAMP` and `POSITION_KIND_BLOCK_NUMBER` |
| `feeds[].filter_fields`  | Valid V3 `FieldFilter.field` values; empty means the feed is not filterable                                                                                                                                      |
| `feeds[].progress`       | Default, minimum, and maximum [progress frame](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) interval in milliseconds; unset means the feed does not support progress frames                                           |

Order-book snapshots are intentionally outside the registry because they are generated from periodic ABCI state rather than exposed as a block-envelope feed. `StreamOrderbookSnapshots` and `GetOrderbookSnapshot` are the public methods for accessing them. Snapshot availability and maximum response size vary by endpoint. Oversized responses return `RESOURCE_EXHAUSTED`.

## Errors

- `UNAUTHENTICATED` or `PERMISSION_DENIED` means the request did not include usable credentials.
- Transport failures and `UNAVAILABLE` should be handled with a bounded retry; keep the last known capabilities only if that fallback is acceptable for your application.

See the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-raw-feed-service) for positioning, filtering, retention, and recovery semantics shared by raw methods.

---

## maxBuilderFee - HyperCore Info Endpoint

# maxBuilderFee - HyperCore Info Endpoint

Get maximum builder fee information on Hyperliquid.

The Dwellir Hyperliquid Info API currently returns `Failed to deserialize the JSON body into the target type` for `maxBuilderFee` requests.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `maxBuilderFee` endpoint is documented by Hyperliquid, but it is not currently usable through this Dwellir Info endpoint.

For builder fee behavior in production workflows, use the HyperCore exchange docs and your exchange account integration.

## Request Parameters

- `type` (`string, required`): parameter: Must be `"maxBuilderFee"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "maxBuilderFee"
}'
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
"Failed to deserialize the JSON body into the target type"
```

## Error Responses

### Error Response

- Code: `422`
- Description: The request payload cannot be deserialized for this method on the Dwellir Hyperliquid Info API.

```json
"Failed to deserialize the JSON body into the target type"
```

## Endpoint Status

`maxBuilderFee` does not currently return a normalized response schema through the Info API. If your workflow depends on this data, use supported exchange-level methods or contact
<support@dwellir.com>.

## Related Endpoints

- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user trading fees
- [**maxMarketOrderNtls**](https://www.dwellir.com/docs/hyperliquid/max-market-order-ntls) — Get maximum market order sizes
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata
- [**exchangeStatus**](https://www.dwellir.com/docs/hyperliquid/exchange-status) — Get exchange status

***

*Access builder fee information with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## maxMarketOrderNtls - HyperCore Info Endpoint

# maxMarketOrderNtls - HyperCore Info Endpoint

Get maximum market order notional values for trading pairs on Hyperliquid, helping traders understand order size limits.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `maxMarketOrderNtls` endpoint is essential for:

- **Order Validation** — Check if order size is within allowed limits
- **Trading Strategy** — Plan large orders based on market constraints
- **Risk Management** — Understand maximum position sizes
- **Market Impact** — Estimate potential market impact of large orders

## Request Parameters

- `type` (`string, required`): parameter: Must be `"maxMarketOrderNtls"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "maxMarketOrderNtls"
}'
```

## Response Fields

- `limits` (`object, required`): Object mapping trading pairs to their maximum market order notional values

## Successful Response

```json
{
  "limits": {}
}
```

## Common Use Cases

### 1. Check Maximum Order Size

Verify if an order size is within limits:

```javascript
async function checkOrderSize(asset, orderValue) {
  const data = await getMaxMarketOrderNtls();
  const maxNotional = data.limits[asset];

  if (!maxNotional) {
    console.log(`No limit data for ${asset}`);
    return null;
  }

  const isValid = orderValue <= parseFloat(maxNotional);

  console.log(`Order size: $${orderValue.toLocaleString()}`);
  console.log(`Maximum allowed: $${parseFloat(maxNotional).toLocaleString()}`);
  console.log(`Valid: ${isValid ? 'Yes' : 'No - exceeds limit'}`);

  return isValid;
}

// Usage
await checkOrderSize('BTC', 50000);
```

### 2. Validate Order Before Submission

Pre-validate orders against limits:

```javascript
async function validateMarketOrder(asset, orderValue) {
  const data = await getMaxMarketOrderNtls();
  const maxNotional = parseFloat(data.limits[asset] || 0);

  if (orderValue > maxNotional) {
    return {
      valid: false,
      reason: `Order size $${orderValue} exceeds maximum $${maxNotional}`,
      maxAllowed: maxNotional
    };
  }

  return {
    valid: true,
    reason: 'Order size within limits',
    maxAllowed: maxNotional
  };
}

// Usage
const validation = await validateMarketOrder('ETH', 100000);
if (!validation.valid) {
  console.error(`Cannot place order: ${validation.reason}`);
}
```

### 3. Calculate Maximum Position Size

Determine maximum position that can be opened:

```javascript
async function getMaxPositionSize(asset, currentPrice) {
  const data = await getMaxMarketOrderNtls();
  const maxNotional = parseFloat(data.limits[asset] || 0);

  const maxPositionSize = maxNotional / currentPrice;

  return {
    asset: asset,
    currentPrice: currentPrice,
    maxNotionalValue: maxNotional,
    maxPositionSize: maxPositionSize,
    unit: asset
  };
}

// Usage
const maxPosition = await getMaxPositionSize('BTC', 45000);
console.log(`Maximum position: ${maxPosition.maxPositionSize.toFixed(4)} ${maxPosition.unit}`);
console.log(`Notional value: $${maxPosition.maxNotionalValue.toLocaleString()}`);
```

### 4. Build Order Size Calculator

Create an order size calculator with validation:

```javascript
async function calculateOrderSizes(asset, currentPrice) {
  const data = await getMaxMarketOrderNtls();
  const maxNotional = parseFloat(data.limits[asset] || 0);

  const suggestions = [0.25, 0.5, 0.75, 1.0].map(percent => {
    const notionalValue = maxNotional * percent;
    const positionSize = notionalValue / currentPrice;

    return {
      percentage: percent * 100,
      notionalValue: notionalValue,
      positionSize: positionSize
    };
  });

  console.log(`=== Order Size Suggestions for ${asset} ===\n`);
  suggestions.forEach(s => {
    console.log(`${s.percentage}% of max: ${s.positionSize.toFixed(4)} ${asset} ($${s.notionalValue.toLocaleString()})`);
  });

  return suggestions;
}

// Usage
await calculateOrderSizes('BTC', 45000);
```

### 5. Monitor Limit Changes

Track changes in order limits:

```javascript
class OrderLimitMonitor {
  constructor(checkIntervalMs = 300000) {
    this.checkIntervalMs = checkIntervalMs; // 5 minutes
    this.lastLimits = null;
  }

  async start() {
    const check = async () => {
      const data = await getMaxMarketOrderNtls();

      if (this.lastLimits) {
        for (const [asset, limit] of Object.entries(data.limits)) {
          const lastLimit = this.lastLimits[asset];
          if (lastLimit && lastLimit !== limit) {
            console.log(`Limit changed for ${asset}: ${lastLimit} -> ${limit}`);
          }
        }
      }

      this.lastLimits = data.limits;
    };

    await check();
    setInterval(check, this.checkIntervalMs);
  }
}

// Usage
const monitor = new OrderLimitMonitor();
monitor.start();
```

### 6. Split Large Orders

Suggest order splitting for sizes exceeding limits:

```javascript
async function splitLargeOrder(asset, desiredValue) {
  const data = await getMaxMarketOrderNtls();
  const maxNotional = parseFloat(data.limits[asset] || 0);

  if (desiredValue <= maxNotional) {
    return {
      needsSplit: false,
      message: 'Order within limits',
      orders: [{ value: desiredValue }]
    };
  }

  const numOrders = Math.ceil(desiredValue / maxNotional);
  const orderSize = desiredValue / numOrders;

  const orders = Array(numOrders).fill(null).map((_, i) => ({
    orderNumber: i + 1,
    value: orderSize
  }));

  return {
    needsSplit: true,
    message: `Split into ${numOrders} orders`,
    totalValue: desiredValue,
    maxPerOrder: maxNotional,
    orders: orders
  };
}

// Usage
const split = await splitLargeOrder('BTC', 200000);
if (split.needsSplit) {
  console.log(`Order needs splitting: ${split.message}`);
  split.orders.forEach(order => {
    console.log(`Order ${order.orderNumber}: $${order.value.toLocaleString()}`);
  });
}
```

## Best Practices

1. **Cache limits** — Order limits change infrequently, cache for 5-10 minutes
2. **Validate before submission** — Always check limits before placing orders
3. **Handle missing data** — Some assets may not have limit data
4. **Use buffer** — Stay 5-10% below maximum to account for price fluctuations
5. **Monitor changes** — Track limit changes that may affect trading strategies

## Performance Tips

### Cached Limit Service

```javascript
class CachedOrderLimitService {
  constructor(cacheDurationMs = 300000) {
    this.cache = null;
    this.cacheTime = 0;
    this.cacheDurationMs = cacheDurationMs; // 5 minutes
  }

  async getLimits() {
    const now = Date.now();

    if (this.cache && (now - this.cacheTime) < this.cacheDurationMs) {
      return this.cache;
    }

    const data = await getMaxMarketOrderNtls();
    this.cache = data;
    this.cacheTime = now;

    return data;
  }

  async getLimitForAsset(asset) {
    const data = await this.getLimits();
    return parseFloat(data.limits[asset] || 0);
  }

  invalidate() {
    this.cache = null;
    this.cacheTime = 0;
  }
}

// Usage
const limitService = new CachedOrderLimitService();
const btcLimit = await limitService.getLimitForAsset('BTC');
```

## Related Endpoints

- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — View current orders
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Check account capacity
- [**maxBuilderFee**](https://www.dwellir.com/docs/hyperliquid/max-builder-fee) — Get builder fee limits

***

*Optimize your trading with order limit information from Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## meta - HyperCore Info Endpoint

# meta - HyperCore Info Endpoint

Get metadata for all available **perpetual futures trading pairs** on Hyperliquid, including leverage limits, decimal precision, margin requirements, and additional platform-level state such as open-interest cap markers and external pricing hints.

This endpoint returns metadata for **perpetual futures markets**. For spot trading metadata, see [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta).

### Example Perpetual Market Entry

The live `meta` response currently returns the same core fields for mainnet perpetual markets, including size precision, leverage limits, and the associated margin table:

```json
{
  "szDecimals": 5,
  "name": "BTC",
  "maxLeverage": 40,
  "marginTableId": 56
}
```

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `meta` endpoint is essential for derivatives traders, trading platforms, and market data providers who need to:

- **Validate Order Parameters** — Ensure orders comply with leverage and size requirements
- **Build Trading Interfaces** — Display available markets with correct decimal precision
- **Market Discovery** — List all tradeable perpetual contracts
- **Risk Management** — Monitor leverage limits and margin requirements
- **Platform State Awareness** — Detect markets that are at open-interest caps or have external pricing metadata attached

## Request Parameters

- `type` (`string, required`): parameter: Must be `"meta"`
- `dex` (`string, optional`): parameter: HIP3 perp DEX identifier. Valid values: `"xyz"`, `"flx"`, `"vntl"`, `"hyna"`, `"cash"`. Omit for Hyperliquid mainnet perpetuals.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "meta"
}'
```

## Response Fields

- `universe` (`array, required`): Array of trading pair objects
- `marginTables` (`array, required`): Array of margin table definitions with tier structures
- `collateralToken` (`integer, required`): Collateral token ID
- `perpsAtOpenInterestCap` (`array, optional`): Optional list of perpetual markets that are currently at their open-interest cap
- `externalPerpPxs` (`object, optional`): Optional mapping of externally sourced perp prices when Hyperliquid exposes them

## Successful Response

```json
{
  "universe": [
    {
      "szDecimals": 5,
      "name": "BTC",
      "maxLeverage": 40,
      "marginTableId": 56
    },
    {
      "szDecimals": 4,
      "name": "ETH",
      "maxLeverage": 25,
      "marginTableId": 55
    },
    {
      "szDecimals": 2,
      "name": "SOL",
      "maxLeverage": 20,
      "marginTableId": 54
    },
    {
      "szDecimals": 1,
      "name": "MATIC",
      "maxLeverage": 20,
      "marginTableId": 20,
      "isDelisted": true
    }
  ],
  "marginTables": [
    [
      56,
      {
        "description": "tiered 40x",
        "marginTiers": [
          {
            "lowerBound": "0.0",
            "maxLeverage": 40
          },
          {
            "lowerBound": "150000000.0",
            "maxLeverage": 20
          }
        ]
      }
    ]
  ],
  "collateralToken": 0
}
```

## Common Use Cases

### 1. Validate Order Leverage

Check if an order's leverage is within allowed limits:

```javascript
async function validateLeverage(asset, leverage) {
  const meta = await getMeta();
  const assetMeta = meta.universe.find(m => m.name === asset);

  if (!assetMeta) {
    throw new Error(`Asset ${asset} not found`);
  }

  if (leverage > assetMeta.maxLeverage) {
    throw new Error(
      `Leverage ${leverage}x exceeds maximum ${assetMeta.maxLeverage}x for ${asset}`
    );
  }

  return true;
}
```

### 2. Format Position Sizes

Format position sizes with correct decimal precision:

```javascript
function formatSize(asset, size, meta) {
  const assetMeta = meta.universe.find(m => m.name === asset);
  if (!assetMeta) return size.toString();

  return size.toFixed(assetMeta.szDecimals);
}

// Usage
const meta = await getMeta();
console.log(formatSize('BTC', 0.123456, meta)); // "0.12345"
console.log(formatSize('ETH', 1.23456, meta));  // "1.2346"
```

### 3. Build Market Selector UI

Create a market selector with leverage information:

```javascript
async function getMarketList() {
  const meta = await getMeta();

  return meta.universe.map(market => ({
    symbol: market.name,
    maxLeverage: market.maxLeverage,
    marginType: market.onlyIsolated ? 'Isolated Only' : 'Cross/Isolated',
    decimals: market.szDecimals
  }));
}

// Usage
const markets = await getMarketList();
markets.forEach(m => {
  console.log(`${m.symbol}: ${m.maxLeverage}x leverage (${m.marginType})`);
});
```

### 4. Cache Metadata

Cache metadata to reduce API calls:

```javascript
class MetaCache {
  constructor(ttl = 3600000) { // 1 hour default
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get() {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await getMeta();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const metaCache = new MetaCache();
```

## Best Practices

1. **Cache metadata** for at least 1 hour as it changes infrequently
2. **Validate leverage** before submitting orders to avoid rejections
3. **Use correct decimals** when formatting position sizes
4. **Handle errors gracefully** with retry logic and fallbacks
5. **Monitor rate limits** to avoid service interruptions
6. **Treat the payload as extensible** because additional metadata fields can appear when Hyperliquid exposes more market state

## Related Endpoints

- [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta) — Get spot trading asset metadata
- [**perpDexs**](https://www.dwellir.com/docs/hyperliquid/perp-dexs) — Get HIP-3 perpetual DEX metadata
- [**exchangeStatus**](https://www.dwellir.com/docs/hyperliquid/exchange-status) — Check exchange health and status
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get user account state with positions
- [**candles**](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles#discovering-markets) — Use perp symbols as the `market` parameter for candle queries

***

*Access real-time Hyperliquid market metadata with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## modify payload - Single Order Modifications

# modify payload - Single Order Modifications

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `modify` payload records a native request to change an existing order's price, size, or other parameters.

## Sample Data

```json
{
  "signature": {
    "r": "0xc99c77b2297349c8ab77d7a820a31e0d43646c9c938775b81b5aed101e89885f",
    "s": "0x881c0298616ca974aad375d044e5796ed719eac0b86cf2f1348e309f623231d",
    "v": 28
  },
  "action": {
    "type": "modify",
    "oid": 291708423670,
    "order": {
      "a": 191,
      "b": true,
      "p": "0.15042",
      "s": "6583",
      "r": false,
      "t": {
        "limit": {
          "tif": "Alo"
        }
      },
      "c": "0x55560089921887924531768146559426"
    }
  },
  "nonce": 1768146528890,
  "vaultAddress": "0x0bd00a003c3a494261789a9c87ff17f6e605e715"
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xff6953a569e4b75500e304332644c201dc006b8b04e7d628a331fef828e89140)

## Field Reference

### Action Fields

| Field   | Type   | Description                             |
| ------- | ------ | --------------------------------------- |
| `type`  | string | Always `"modify"`                       |
| `oid`   | string | Order ID (or client order ID) to modify |
| `order` | object | New order parameters                    |

### Order Object Fields

| Field | Type    | Description                            |
| ----- | ------- | -------------------------------------- |
| `a`   | number  | Asset index                            |
| `b`   | boolean | Side: `true` for buy, `false` for sell |
| `p`   | string  | New limit price                        |
| `s`   | string  | New size                               |
| `r`   | boolean | Reduce-only flag                       |
| `t`   | object  | Order type configuration               |
| `c`   | string  | Client order ID                        |

### Optional Fields

| Field          | Type   | Description                      |
| -------------- | ------ | -------------------------------- |
| `vaultAddress` | string | Vault executing the modification |
| `expiresAfter` | number | Expiration timestamp             |

## Use Cases

### Order Update Tracking

Monitor how traders adjust their orders:

```python
def process_modify_action(action):
    oid = action.get('oid')
    order = action.get('order', {})
    new_price = order.get('p')
    new_size = order.get('s')

    print(f"Order {oid[:10]}... modified: price={new_price}, size={new_size}")
```

### Market Maker Analysis

Track how frequently market makers update their quotes.

### Price Improvement Detection

Monitor price improvements on existing orders.

## Related Action Payloads

- [order](https://www.dwellir.com/docs/hyperliquid/order) - New order payloads
- [batchModify](https://www.dwellir.com/docs/hyperliquid/batchModify) - Batched order modifications
- [cancel](https://www.dwellir.com/docs/hyperliquid/cancel) - Order cancellations

---

## multiSig payload - Multi-Signature Operations

# multiSig payload - Multi-Signature Operations

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `multiSig` payload records an action authorized by multiple signatures under a multi-signature account policy.

## Sample Data

```json
{
  "signature": {
    "r": "0xa9b99251bf412a7cf584710c1ed25328dbe8523ae65f01911211a51cd63b3072",
    "s": "0x27883f0ff43062e012fabc1a192d12212c9cbe7f6939a0429fffe44f1779eb52",
    "v": 27
  },
  "action": {
    "type": "multiSig",
    "signatureChainId": "0x3e7",
    "signatures": [
      {
        "r": "0xae84dedfe9ad13036d95dfa84c8e47cfd8f28fd191ac582f7ebba02cdadecb6a",
        "s": "0x5ba85eea603c524c50b722b7b3342ed3e1eec4c6dc491b3fc9dc5769a76d1deb",
        "v": 28
      }
    ],
    "payload": {
      "multiSigUser": "0x1234567890545d1df9ee64b35fdd16966e08acec",
      "outerSigner": "0xd2d8bc14967d340c1eebde6eec6358200278da91",
      "action": {
        "type": "perpDeploy",
        "setOracle": {
          "dex": "xyz",
          "oraclePxs": [["xyz:AAPL", "260.02"], ["xyz:AMD", "203.72"]]
        }
      }
    }
  },
  "nonce": 1768146913280
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x08dbe3e6b517f2e30a55043326066f0201e600cc501b11b5aca48f39741bcccd)

## Field Reference

### Action Fields

| Field              | Type   | Description                   |
| ------------------ | ------ | ----------------------------- |
| `type`             | string | Always `"multiSig"`           |
| `signatureChainId` | string | Chain ID for EIP-712 signing  |
| `signatures`       | array  | Array of co-signer signatures |
| `payload`          | object | The wrapped action to execute |

### Payload Fields

| Field          | Type   | Description                        |
| -------------- | ------ | ---------------------------------- |
| `multiSigUser` | string | Address of the multi-sig account   |
| `outerSigner`  | string | Address of the signature submitter |
| `action`       | object | The underlying action to execute   |

## Multi-Sig Benefits

- **Enhanced Security**: Requires multiple parties to authorize actions
- **Institutional Control**: Enables proper governance for fund operations
- **Recovery Options**: Prevents single point of failure

## Use Cases

### Institutional Activity Tracking

Monitor multi-sig operations for institutional-grade accounts:

```python
def process_multiSig_action(action):
    payload = action.get('payload', {})
    multisig_user = payload.get('multiSigUser')
    inner_action = payload.get('action', {})
    inner_type = inner_action.get('type')

    print(f"MultiSig: {inner_type} from {multisig_user[:10]}...")
```

### Oracle Price Updates

Many multi-sig actions are used for oracle price feeds (as shown in the sample).

### Governance Analysis

Track how multi-sig accounts manage critical protocol operations.

## Related Action Payloads

- [convertToMultiSigUser](https://www.dwellir.com/docs/hyperliquid/convertToMultiSigUser) - Multi-signature conversion
- [perpDeploy](https://www.dwellir.com/docs/hyperliquid/perpDeploy) - Perpetual market deployments (often wrapped in multiSig)

---

## net_listening - Hyperliquid RPC Method

# net_listening - Hyperliquid RPC Method

Checks whether the connected Hyperliquid client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`net_listening` is useful for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Hyperliquid node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Hyperliquid node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Hyperliquid node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/hyperliquid/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/hyperliquid/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/hyperliquid/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/hyperliquid/web3_clientVersion) - Get node client info

---

## net_peerCount - Hyperliquid RPC Method

# net_peerCount - Hyperliquid RPC Method

Returns the number of peers currently connected to your Hyperliquid node.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`net_peerCount` is important for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Hyperliquid deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Hyperliquid peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Hyperliquid peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Hyperliquid peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Hyperliquid nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/hyperliquid/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/hyperliquid/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/hyperliquid/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/hyperliquid/web3_clientVersion) - Get node client info

---

## net_version - Hyperliquid RPC Method

# net_version - Hyperliquid RPC Method

Returns the current network ID on Hyperliquid as a decimal string. The network ID identifies which network the node is connected to.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`net_version` is essential for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Endpoint Identification** - Confirm your application is connected to the expected Hyperliquid network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Current Network ID

Hyperliquid shared HyperEVM endpoints currently report `999` from `net_version`. Use that value to confirm you are connected to the expected HyperEVM mainnet surface before signing or routing requests.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Hyperliquid network ID:', networkId);

// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Hyperliquid network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Hyperliquid network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/hyperliquid/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/hyperliquid/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/hyperliquid/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/hyperliquid/eth_syncing) - Check node sync progress

---

## NetChildVaultPositionsAction payload - Child Vault Positions

# NetChildVaultPositionsAction payload - Child Vault Positions

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `NetChildVaultPositionsAction` payload records a request to net selected asset positions across child vaults for consolidated risk management and reconciliation.

## Sample Data

```json
{
  "signature": {
    "r": "0xd84c596af3ebf2fed0a6a73a04bf11c4602534e53bca68175f8036f5d087052a",
    "s": "0x7d00b1602687f3e7143559df0f7a8dd7b37dce46d7e463dcb49867df613a30c6",
    "v": 28
  },
  "action": {
    "type": "NetChildVaultPositionsAction",
    "childVaultAddresses": [
      "0x010461c14e146ac35fe42271bdc1134ee31c703a",
      "0x31ca8395cf837de08b24da3f660e77761dfb974b"
    ],
    "assets": [22, 34, 52]
  },
  "nonce": 1768146734567,
  "vaultAddress": "0xdfc24b077bc1425ad1dea75bcb6f8158e10df303"
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x115e4ffc86b151e312d8043326460402016700e221b470b5b526fb4f45b52bcd)

## Field Reference

### Action Fields

| Field                 | Type   | Description                             |
| --------------------- | ------ | --------------------------------------- |
| `type`                | string | Always `"NetChildVaultPositionsAction"` |
| `childVaultAddresses` | array  | Child vault addresses to net            |
| `assets`              | array  | Asset indices to net positions for      |

## Use Cases

### Vault Position Management

Track position netting across child vaults:

```python
def process_NetChildVaultPositionsAction(action):
    children = action.get('childVaultAddresses', [])
    assets = action.get('assets', [])
    print(f"Netting {len(assets)} assets across {len(children)} vaults")
```

## Related Action Payloads

- [vaultTransfer](https://www.dwellir.com/docs/hyperliquid/vaultTransfer) - Vault deposits/withdrawals

---

## noop payload - Nonce Invalidation

# noop payload - Nonce Invalidation

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `noop` payload records a no-operation request that marks the submitted nonce as used without placing or canceling an order.

## Sample Data

```json
{
  "signature": {
    "r": "0x5157d93e3d66571991b0a7aa9cbfd108a7fff13749c606348acc14374bbbc9cd",
    "s": "0x42d4ed4d0863958c8bae8df8650b6844021168eb385f0ee0c085ae897f279c70",
    "v": 28
  },
  "action": {
    "type": "noop"
  },
  "nonce": 1768146879398,
  "vaultAddress": "0x3ac9b030594c1ef23a3e8fed9f62356b7bf98bf6"
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x7b1200a2ac5608677c8b04332643de010f001888475927391edaabf56b59e252)

## Field Reference

### Action Fields

| Field  | Type   | Description     |
| ------ | ------ | --------------- |
| `type` | string | Always `"noop"` |

### Optional Fields

| Field          | Type   | Description                                    |
| -------------- | ------ | ---------------------------------------------- |
| `vaultAddress` | string | Vault executing the noop (if vault-originated) |

## Nonce Effect

Although `noop` performs no trading operation, it changes nonce state. Hyperliquid marks the nonce as used, which can invalidate in-flight actions signed with that nonce. Preserve the nonce and signer when indexing these payloads so the invalidation can be correlated with other submitted actions.

## Use Cases

### Trading Activity Filtering

Filter out noops when analyzing real trading activity:

```python
def process_block_actions(actions):
    # Filter out noops to focus on real activity
    real_actions = [a for a in actions if a.get('type') != 'noop']
    return real_actions
```

### Nonce Invalidation Tracking

Record the signer and used nonce when analyzing actions that may have been invalidated:

```python
def record_noop(bundle):
    action = bundle.get('action', {})
    if action.get('type') == 'noop':
        print(f"Nonce marked used: {bundle.get('nonce')}")
```

## Related Action Payloads

- [order](https://www.dwellir.com/docs/hyperliquid/order) - Real trading activity
- [SetGlobalAction](https://www.dwellir.com/docs/hyperliquid/SetGlobalAction) - System configuration

---

## openOrders - HyperCore Info Endpoint

# openOrders - HyperCore Info Endpoint

Get all open limit orders for a user on Hyperliquid perpetual markets.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `openOrders` endpoint is essential for traders, trading platforms, and market makers who need to:

- **Order Management** — Monitor and manage active limit orders
- **Trading Bots** — Track order status and execution
- **Market Making** — Monitor spread and order book participation
- **Portfolio Management** — Track pending orders across multiple markets

## Request Parameters

- `type` (`string, required`): parameter: Must be `"openOrders"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "openOrders",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `coin` (`string, required`): Trading pair symbol (e.g., "BTC", "ETH")
- `side` (`string, required`): Order side: `"B"` for buy, `"A"` for ask/sell
- `limitPx` (`string, required`): Limit price for the order
- `sz` (`string, required`): Current remaining order size
- `oid` (`integer, required`): Unique order ID
- `timestamp` (`integer, required`): Order creation timestamp in milliseconds
- `origSz` (`string, required`): Original order size when placed
- `cloid` (`string, required`): Client order ID (hexadecimal string)

## Successful Response

```json
[
  {
    "coin": "BTC",
    "side": "B",
    "limitPx": "69043.0",
    "sz": "0.29596",
    "oid": 316509475419,
    "timestamp": 1770639841704,
    "origSz": "0.29596",
    "cloid": "0x00000000000000000000019c4151ce32"
  },
  {
    "coin": "ETH",
    "side": "A",
    "limitPx": "2034.3",
    "sz": "12.1703",
    "oid": 316509474405,
    "timestamp": 1770639841704,
    "origSz": "12.1703",
    "cloid": "0x00000000000000000000019c4151ce2f"
  }
]
```

## Common Use Cases

### 1. Monitor Order Fill Progress

Track how much of each order has been filled:

```javascript
async function getOrderFillProgress(userAddress) {
  const orders = await getOpenOrders(userAddress);

  return orders.map(order => {
    const orig = parseFloat(order.origSz);
    const remaining = parseFloat(order.sz);
    const filled = orig - remaining;
    const fillPercent = (filled / orig) * 100;

    return {
      orderId: order.oid,
      coin: order.coin,
      side: order.side === 'B' ? 'BUY' : 'SELL',
      price: parseFloat(order.limitPx),
      originalSize: orig,
      remainingSize: remaining,
      filledSize: filled,
      fillPercent: fillPercent.toFixed(2),
      isPartiallyFilled: fillPercent > 0 && fillPercent < 100
    };
  });
}

// Usage
const progress = await getOrderFillProgress('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
const partialFills = progress.filter(o => o.isPartiallyFilled);
console.log(`${partialFills.length} partially filled orders`);
```

### 2. Calculate Total Order Book Exposure

Calculate total capital committed in open orders:

```javascript
async function calculateOrderExposure(userAddress) {
  const orders = await getOpenOrders(userAddress);

  const totalExposure = orders.reduce((sum, order) => {
    const size = parseFloat(order.sz);
    const price = parseFloat(order.limitPx);
    return sum + (size * price);
  }, 0);

  const byMarket = orders.reduce((acc, order) => {
    const size = parseFloat(order.sz);
    const price = parseFloat(order.limitPx);
    const exposure = size * price;

    if (!acc[order.coin]) {
      acc[order.coin] = { buy: 0, sell: 0, total: 0 };
    }

    if (order.side === 'B') {
      acc[order.coin].buy += exposure;
    } else {
      acc[order.coin].sell += exposure;
    }
    acc[order.coin].total += exposure;

    return acc;
  }, {});

  return {
    totalExposure: totalExposure,
    byMarket: byMarket,
    orderCount: orders.length
  };
}
```

### 3. Find Stale Orders

Identify orders that have been open for a long time:

```javascript
async function findStaleOrders(userAddress, hoursThreshold = 24) {
  const orders = await getOpenOrders(userAddress);
  const now = Date.now();
  const thresholdMs = hoursThreshold * 60 * 60 * 1000;

  const staleOrders = orders.filter(order => {
    return (now - order.timestamp) > thresholdMs;
  });

  return staleOrders.map(order => ({
    orderId: order.oid,
    coin: order.coin,
    side: order.side === 'B' ? 'BUY' : 'SELL',
    price: order.limitPx,
    size: order.sz,
    ageHours: ((now - order.timestamp) / (1000 * 60 * 60)).toFixed(1)
  }));
}

// Usage
const stale = await findStaleOrders('0x63E8c7C149556D5f34F833419A287bb9Ef81487f', 48);
console.log(`${stale.length} orders older than 48 hours`);
stale.forEach(o => {
  console.log(`${o.coin} ${o.side} @ $${o.price} (${o.ageHours}h old)`);
});
```

### 4. Group Orders by Market

Organize orders by trading pair:

```javascript
async function groupOrdersByMarket(userAddress) {
  const orders = await getOpenOrders(userAddress);

  const grouped = orders.reduce((acc, order) => {
    if (!acc[order.coin]) {
      acc[order.coin] = {
        buy: [],
        sell: [],
        totalBuySize: 0,
        totalSellSize: 0
      };
    }

    const side = order.side === 'B' ? 'buy' : 'sell';
    acc[order.coin][side].push(order);

    if (side === 'buy') {
      acc[order.coin].totalBuySize += parseFloat(order.sz);
    } else {
      acc[order.coin].totalSellSize += parseFloat(order.sz);
    }

    return acc;
  }, {});

  return grouped;
}

// Usage
const byMarket = await groupOrdersByMarket('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
Object.entries(byMarket).forEach(([coin, data]) => {
  console.log(`\n${coin}:`);
  console.log(`  ${data.buy.length} buy orders (${data.totalBuySize} total)`);
  console.log(`  ${data.sell.length} sell orders (${data.totalSellSize} total)`);
});
```

### 5. Order Management Dashboard

Create a comprehensive order dashboard:

```javascript
async function getOrderDashboard(userAddress) {
  const orders = await getOpenOrders(userAddress);

  const now = Date.now();
  const stats = {
    totalOrders: orders.length,
    buyOrders: orders.filter(o => o.side === 'B').length,
    sellOrders: orders.filter(o => o.side === 'A').length,
    markets: [...new Set(orders.map(o => o.coin))],
    partiallyFilled: orders.filter(o => o.sz !== o.origSz).length,
    averageAge: orders.reduce((sum, o) => sum + (now - o.timestamp), 0) / orders.length / (1000 * 60 * 60)
  };

  console.log('=== Order Dashboard ===');
  console.log(`Total Orders: ${stats.totalOrders}`);
  console.log(`  Buy: ${stats.buyOrders}`);
  console.log(`  Sell: ${stats.sellOrders}`);
  console.log(`Markets: ${stats.markets.join(', ')}`);
  console.log(`Partially Filled: ${stats.partiallyFilled}`);
  console.log(`Average Age: ${stats.averageAge.toFixed(1)} hours`);

  return stats;
}
```

## Best Practices

1. **Poll at appropriate intervals** — Poll every 5-10 seconds for active trading, less frequently for monitoring
2. **Handle empty arrays** — User may have no open orders
3. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
4. **Track order IDs** — Use order IDs to track specific orders across polls
5. **Monitor fill rates** — Alert when orders are partially filled

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state with positions
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user fee rates
- [**frontendOpenOrders**](https://www.dwellir.com/docs/hyperliquid/frontend-open-orders) — Get formatted orders for frontend display
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata

***

*Access real-time Hyperliquid order data with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## order payload - Trading Orders

# order payload - Trading Orders

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `order` action payload records one or more limit, market, or trigger orders submitted to Hyperliquid. It is the most frequently observed trading action in Hyperliquid block data.

## Sample Data

```json
{
  "signature": {
    "r": "0x961237313a71a702d4ca5f870a32172f3929aa9328d80505cbc5b9b178d2e338",
    "s": "0x8d0bc7bb0119bf5daac5e93a9552166e4a2f10bd711c26909e206aeb81eac89",
    "v": 28
  },
  "action": {
    "type": "order",
    "orders": [
      {
        "a": 216,
        "b": false,
        "p": "0.26832",
        "s": "2021",
        "r": false,
        "t": {
          "limit": {
            "tif": "Ioc"
          }
        },
        "c": "0x00000000000000000b56a217a8ef1f3c"
      }
    ],
    "grouping": "na"
  },
  "nonce": 1768146912522,
  "expiresAfter": 1768146932522
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x72715093ba5096f673eb04332644bd02015400795553b5c81639fbe6795470e1)

## Field Reference

### Action Fields

| Field      | Type   | Description                                                                 |
| ---------- | ------ | --------------------------------------------------------------------------- |
| `type`     | string | Always `"order"`                                                            |
| `orders`   | array  | Array of order objects to submit                                            |
| `grouping` | string | Order grouping strategy: `"na"` (none), `"normalTpsl"`, or `"positionTpsl"` |

### Order Object Fields

| Field | Type    | Description                      |
| ----- | ------- | -------------------------------- |
| `a`   | number  | Asset index (e.g., 0=BTC, 1=ETH) |
| `b`   | boolean | `true` for buy, `false` for sell |
| `p`   | string  | Limit price                      |
| `s`   | string  | Size in base currency            |
| `r`   | boolean | Reduce-only flag                 |
| `t`   | object  | Order type configuration         |
| `c`   | string  | Client order ID (optional)       |

### Order Type Configuration

The `t` field specifies order execution behavior:

```json
// Limit order with time-in-force
{ "limit": { "tif": "Gtc" } }  // Good-til-canceled
{ "limit": { "tif": "Ioc" } }  // Immediate-or-cancel
{ "limit": { "tif": "Alo" } }  // Add-liquidity-only (post-only)

// Market order
{ "trigger": { "isMarket": true, "triggerPx": "0", "tpsl": "tp" } }
```

### Optional Fields

| Field          | Type   | Description                                  |
| -------------- | ------ | -------------------------------------------- |
| `vaultAddress` | string | Vault executing the order (if vault trading) |
| `expiresAfter` | number | Expiration timestamp in milliseconds         |

## Use Cases

### Order Flow Analysis

Track all order submissions to understand market activity:

```python
def process_order_action(action):
    for order in action.get('orders', []):
        asset = order['a']
        side = 'BUY' if order['b'] else 'SELL'
        price = order['p']
        size = order['s']

        print(f"New order: {side} {size} @ {price} (asset {asset})")
```

### Trading Bot Monitoring

Monitor competitor or whale trading activity by tracking order submissions from specific addresses.

### Market Microstructure Research

Analyze order placement patterns, timing, and pricing strategies across the Hyperliquid order book.

## Related Action Payloads

- [cancel](https://www.dwellir.com/docs/hyperliquid/cancel) - Order cancellations by ID
- [cancelByCloid](https://www.dwellir.com/docs/hyperliquid/cancelByCloid) - Order cancellations by client ID
- [batchModify](https://www.dwellir.com/docs/hyperliquid/batchModify) - Batched order modifications
- [modify](https://www.dwellir.com/docs/hyperliquid/modify) - Single-order modifications

---

## Hyperliquid Order Book WebSocket API

# Hyperliquid Order Book WebSocket API

Dwellir provides a high-performance WebSocket service for real-time Hyperliquid order-book data, designed for lower and more consistent latency than public API endpoints.

## Pricing and access

The Order Book add-on costs $199/month on an API plan, plus metered usage: each streamed message costs 1 API credit. The [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster) starts at $4,000/month and 2 dedicated backend nodes, and includes both add-ons with unmetered access.

The order book WebSocket serves the derived surfaces — trades, L2/L4 books, and BBO. To see how they relate to raw node feeds and historical products, start from [How Hyperliquid works](https://www.dwellir.com/docs/hyperliquid#how-hyperliquid-works).

Not sure which plan fits your trading strategy? Use our [**Volume Calculator**](https://www.dwellir.com/hyperliquid-orderbook#calculator) to estimate monthly message volume and get a personalized pricing recommendation.

## Watch the WebSocket Walkthrough

## Available Subscription Types

The WebSocket API provides four distinct data streams, each designed for specific use cases:

| Subscription                                                        | Data Type                  | Best For                                                            |
| ------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------- |
| [**Trades**](https://www.dwellir.com/docs/hyperliquid/trades)            | Real-time trade executions | Trade flow analysis, VWAP calculation, execution monitoring         |
| [**L2 Order Book**](https://www.dwellir.com/docs/hyperliquid/l2-book)    | Aggregated price levels    | Spread analysis, market making, liquidity assessment                |
| [**BBO (Best Bid/Offer)**](https://www.dwellir.com/docs/hyperliquid/bbo) | Top-of-book bid/ask        | Price tracking, execution triggers, low-bandwidth spread monitoring |
| [**L4 Order Book**](https://www.dwellir.com/docs/hyperliquid/l4-book)    | Individual orders          | Queue position tracking, whale watching, microstructure analysis    |

### Trades Stream

Stream real-time trade executions as they occur on Hyperliquid. Each trade includes price, size, direction, and participant addresses. Supports optional **user filtering** to receive only trades involving a specific wallet address.

**Ideal for:**

- Volume-weighted average price (VWAP) calculations
- Trade flow and momentum analysis
- Execution quality monitoring
- Per-wallet trade tracking and fill monitoring
- Historical trade data collection

[**View Trades Documentation →**](https://www.dwellir.com/docs/hyperliquid/trades)

### L2 Order Book (Level 2)

Aggregated order book data showing total size at each price level. Supports configurable depth and price aggregation for bandwidth optimization.

**Ideal for:**

- Bid-ask spread monitoring
- Market making strategies
- Liquidity depth analysis
- Support/resistance level detection

[**View L2 Order Book Documentation →**](https://www.dwellir.com/docs/hyperliquid/l2-book)

### BBO (Best Bid/Offer)

Top-of-book stream delivering just the best bid and best ask with minimal bandwidth. Mirrors Hyperliquid's public `bbo` channel. Subscribe with `{"type": "bbo", "coin": "BTC"}` (coin only) to receive the same payload shape. A message is emitted only when the top bid or ask changes, at most once per block.

**Ideal for:**

- Lightweight price tracking and tickers
- Execution and alert triggers
- Spread monitoring with minimal bandwidth
- Drop-in replacement for the public BBO feed

[**View BBO Documentation →**](https://www.dwellir.com/docs/hyperliquid/bbo)

### L4 Order Book (Level 4)

The most detailed market data available - individual order visibility with user addresses, order IDs, timestamps, and full order parameters.

**Ideal for:**

- Queue position optimization
- Whale wallet tracking
- Market microstructure research
- Order flow toxicity analysis

[**View L4 Order Book Documentation →**](https://www.dwellir.com/docs/hyperliquid/l4-book)

## Data Flow Between Channels

The three subscription types serve different purposes and contain different data. Understanding which data lives where prevents common integration pitfalls.

```
Hyperliquid Node
  |
  |-- order_statuses --> L4 Book channel (status transitions: open, filled, canceled)
  |-- book_diffs ------> L4 Book channel (order additions, removals, size changes)
  |-- fills -----------> Trades channel  (execution price, size, hash, wallets)
  |                      L2 Book channel (aggregated from book state)
```

**Key point:** Individual fill details (execution price, counterparty, transaction hash) are only available on the **Trades** stream. The L4 Book channel reports order status changes but not per-fill data. To track an order from placement through each fill to completion, subscribe to both L4 Book and Trades.

For a detailed walkthrough, see [Understanding Order Data Flow](https://www.dwellir.com/docs/hyperliquid/l4-book#understanding-order-data-flow) in the L4 Book documentation.

## Key Features

- **Ultra-low latency** - An optimized delivery path reduces public API overhead
- **Full market depth** - Access to L4 data with individual order visibility
- **Real-time streaming** - WebSocket push model for immediate updates
- **Efficient compression** - Optimized bandwidth usage for high-frequency data
- **Institutional grade** - Professional infrastructure with monitoring and support

## Performance Benchmarks

Based on real-world benchmarking of 2,662 matched trades:

| Metric         | Public API | Dwellir WebSocket | Improvement           |
| -------------- | ---------- | ----------------- | --------------------- |
| Median Latency | 263ms      | 212ms             | **51ms faster (24%)** |
| Mean Latency   | 368ms      | 339ms             | 29ms faster (8%)      |
| Max Latency    | 9,118ms    | 1,977ms           | 7,141ms faster        |

**Win rate**: WebSocket delivers data faster in **75.5%** of cases.

## Quick Start

Connect to the WebSocket endpoint and subscribe to your desired data streams:

```
wss://api-hyperliquid-mainnet-orderbook.n.dwellir.com/{API_KEY}/ws
```

Replace `{API_KEY}` with the API key from your [Dwellir dashboard](https://dashboard.dwellir.com). The Order Book add-on must be enabled on your API plan.

Python
JavaScript

```python
import asyncio
import json
import websockets

async def main():
    ws_url = "wss://api-hyperliquid-mainnet-orderbook.n.dwellir.com/{API_KEY}/ws"

    async with websockets.connect(ws_url) as websocket:
        # Subscribe to BTC trades
        await websocket.send(json.dumps({
            "method": "subscribe",
            "subscription": {"type": "trades", "coin": "BTC"}
        }))

        # Listen for messages
        async for message in websocket:
            data = json.loads(message)
            print(f"Received: {data}")

if __name__ == "__main__":
    asyncio.run(main())
```

```javascript
const WebSocket = require('ws');

const ws = new WebSocket('wss://api-hyperliquid-mainnet-orderbook.n.dwellir.com/{API_KEY}/ws');

ws.on('open', () => {
    // Subscribe to BTC trades
    ws.send(JSON.stringify({
        method: 'subscribe',
        subscription: { type: 'trades', coin: 'BTC' }
    }));
});

ws.on('message', (data) => {
    const message = JSON.parse(data);
    console.log('Received:', message);
});
```

Clone our complete examples: [github.com/dwellir-public/hyperliquid-orderbook-server-code-examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)

## Message Protocol

### Subscribe to Data Stream

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "trades",  // or "l2Book", "bbo", or "l4Book"
    "coin": "BTC"
    // Additional parameters vary by type
  }
}
```

### Unsubscribe from Data Stream

```json
{
  "method": "unsubscribe",
  "subscription": {
    // Same subscription object used to subscribe
  }
}
```

### Server Responses

**Subscription Confirmation:**

```json
{
  "channel": "subscriptionResponse",
  "data": {
    "method": "subscribe",
    "subscription": { /* echoed subscription */ }
  }
}
```

**Error Messages:**

```json
{
  "channel": "error",
  "data": "Descriptive error message"
}
```

Common errors include: `"coin not found"`, `"n_levels too high"`, `"Already subscribed"`, `"Order book not ready"`.

## Use Cases by Industry

### Quantitative Trading

| Use Case               | Recommended Stream | Why                          |
| ---------------------- | ------------------ | ---------------------------- |
| High-frequency trading | L4 Book            | Queue position optimization  |
| Statistical arbitrage  | L2 Book + Trades   | Cross-market spread analysis |
| Momentum strategies    | Trades             | Trade flow direction         |

### Market Making

| Use Case          | Recommended Stream | Why                          |
| ----------------- | ------------------ | ---------------------------- |
| Spread management | L2 Book            | Real-time bid/ask monitoring |
| Inventory risk    | L4 Book            | See competing orders         |
| Quote adjustment  | Trades             | Execution feedback           |

### Analytics & Research

| Use Case              | Recommended Stream | Why                       |
| --------------------- | ------------------ | ------------------------- |
| Market microstructure | L4 Book            | Individual order analysis |
| Liquidity studies     | L2 Book            | Depth at price levels     |
| Volume analysis       | Trades             | Complete trade history    |

## Connection Best Practices

The server may restart occasionally to resync order book state. Your client **must** include automatic reconnection with exponential backoff.

Connection setup can delay the first update. Measure source timestamps and block positions separately from handshake time. Resubscribe after reconnecting and rebuild book state from the opening snapshot before applying diffs. See [freshness and recovery checks](https://www.dwellir.com/docs/hyperliquid/troubleshooting).

```python
class RobustWSClient:
    def __init__(self, ws_url):
        self.ws_url = ws_url
        self.reconnect_delay = 1
        self.max_delay = 60

    async def connect_with_retry(self):
        while True:
            try:
                async with websockets.connect(self.ws_url) as ws:
                    self.reconnect_delay = 1  # Reset on success
                    await self.handle_connection(ws)
            except Exception as e:
                print(f"Connection error: {e}")
                await asyncio.sleep(self.reconnect_delay)
                self.reconnect_delay = min(self.reconnect_delay * 2, self.max_delay)
```

## Get Started

### Hosted WebSocket Service

Dwellir offers production-ready WebSocket servers with:

- **Optimized delivery** - Low-latency access to real-time market data
- **Geographic distribution** - Servers in Singapore and Tokyo
- **99.99% uptime SLA** - Enterprise reliability
- **Dedicated support** - Direct access to engineering team

### Resources

- **[Volume Calculator](https://www.dwellir.com/hyperliquid-orderbook#calculator)** - Estimate your monthly usage
- **[Code Examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)** - Production-ready implementations
- **[Pricing](https://www.dwellir.com/hyperliquid-orderbook)** - Plans for every scale

### Contact Us

Ready to integrate ultra-low latency Hyperliquid data?

- **Email**: <support@dwellir.com>
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Access institutional-grade Hyperliquid market data with Dwellir's ultra-low latency WebSocket infrastructure.*

---

## Hyperliquid Peering

# Hyperliquid Peering

Dedicated, SLA-backed gossip peers for the Hyperliquid node you run yourself. Priced at $500/month per peering slot. A peering slot allowlists one of your node IPs on Dwellir's peering infrastructure.

You keep operating your own node. Dwellir reserves a peer slot for it, so your node keeps a stable upstream instead of competing for public root peers.

Peering is for teams that operate their own Hyperliquid node. If you want Dwellir to run the node and the data services, see the [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster) instead.

## What you get

| Included                          | Detail                                                                                                                                 |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **1 peering slot**                | You send the public IP of your node. Dwellir allowlists it on all three peers. One slot covers one node IP                             |
| **3 Dwellir peers to connect to** | List all three in your config. Your node connects to one peer at a time. If that peer goes down, it reconnects to one of the other two |
| **Full gossip**                   | Blocks and full mempool, the same stream Dwellir's own nodes consume                                                                   |
| **99.9% uptime SLA**              | Measured per calendar month on gossip reachability                                                                                     |
| **Flat $500/month**               | Per peering slot. No bandwidth or egress charges                                                                                       |

All three peers run in one region. This gives you redundancy across hosts, not across regions. If you need a peer in a second geography, contact Dwellir before you subscribe to confirm what is available.

## Why peering matters

Your Hyperliquid node keeps one peer connection that actually feeds it. You live and die by that peer's throughput and uptime. If it is slow, your node is slow. If it drops, your node stops.

The community root peers listed by the `gossipRootIps` API are shared and oversubscribed, and the one you land on is a dice roll. Their addresses change and their slots fill, so the peer that worked yesterday may not take you today.

When your node loses its peer it stops advancing, falls behind the tip, and restarts sync. Downstream that means stale order books, missing fills, and gaps in whatever you write to disk.

A reserved slot removes the dice roll. Your node's IP sits in `reserved_peer_ips` on all three Dwellir peers, so a slot is held for you whether or not the network is busy, and you know which machine you are pulling from.

## Requirements

Before you subscribe, confirm the following about your node:

1. **Ports 4001 and 4002 are open to the public internet.** Hyperliquid uses them for gossip. A node that does not accept inbound connections on these ports gets deprioritized by every peer in the network, including ours.
2. **You have a static public egress IP.** Dwellir allowlists that exact address. Dynamic IPs and large NAT ranges do not work.
3. **You run `hl-visor` in non-validator mode** on Mainnet.

## Setup

Allowlisting is a manual change on the Dwellir side. Expect your peer IPs within one business day of sending your node IP. Once you subscribe, Dwellir sets up a shared Telegram or Slack Connect channel so you can reach the team directly.

### 1. Request access

Email [support@dwellir.com](mailto:support@dwellir.com?subject=Hyperliquid%20Peering) or send a Telegram DM to [@dwellirgrowth](https://t.me/dwellirgrowth) with:

- The public IP of each node you want to peer
- The region your node runs in

### 2. Receive your peer IPs

Dwellir adds each node IP to `reserved_peer_ips` on all three peers and returns three peer addresses.

### 3. Point your node at them

Write the peer IPs into `~/override_gossip_config.json`:

```json
{
  "root_node_ips": [{ "Ip": "<DWELLIR_PEER_1>" }, { "Ip": "<DWELLIR_PEER_2>" }, { "Ip": "<DWELLIR_PEER_3>" }],
  "try_new_peers": false,
  "chain": "Mainnet",
  "reserved_peer_ips": []
}
```

Replace the placeholders with the three peer IPs Dwellir sends you.

Keep `try_new_peers` set to `false`. With `true`, your node discovers and connects to arbitrary peers off the public network, which puts you back on the dice roll you are paying to avoid. With `false`, it talks to the Dwellir peers and nothing else.

If you need the mempool, also set `split_client_blocks` to `true` so the node surfaces uncommitted transactions.

### 4. Restart and confirm

Restart `hl-visor`, then confirm the node keeps applying blocks. The node writes a new file per block batch under its data directory, so the newest file should be seconds old:

```bash
find ~/hl/data/replica_cmds -type f -newermt '-1 minute' | tail -5
```

If the newest file stops advancing, or the visor logs show repeated peer disconnects, send the logs to Dwellir support and the reserved slot gets checked from the peer side.

## Service level

**Uptime: 99.9% per calendar month, per peer.** Dwellir measures gossip reachability on ports 4001 and 4002 from outside its own network. Scheduled maintenance is announced at least 48 hours ahead and is excluded from the measurement.

**No preferential treatment.** Every peering subscriber gets the same peers, the same configuration, and the same priority. Dwellir's own infrastructure runs on these same peers, on the same terms. Dwellir does not run a faster path for market makers, for itself, or for any individual customer. If you have evidence otherwise, email [support@dwellir.com](mailto:support@dwellir.com?subject=Hyperliquid%20Peering%20Compliance). Dwellir will investigate and publish the result.

## Pricing

**$500/month flat**, per peering slot. A peering slot allowlists one of your node IPs on Dwellir's peering infrastructure.

- 3 Dwellir peers to connect to, single region
- Full mempool gossip
- 99.9% uptime SLA
- No usage, bandwidth, or egress charges
- Monthly billing, cancel any time

Request Peering Access

Prefer Telegram? DM [@dwellirgrowth](https://t.me/dwellirgrowth).

## What peering does not include

Peering gives your node a reliable upstream. It does not give you data services.

Those are powered by the client the Dwellir team built, which streams the raw files a Hyperliquid node writes to disk over gRPC, reconstructs order books, and indexes history. If you would rather consume that than run and maintain a node, start here:

## Frequently asked questions

### Can I peer more than one node?

Yes. Each node needs its own peering slot at $500/month, because a slot allowlists one node IP. Each node also needs its own static egress IP.

### What happens if I change my node's IP?

Send the new address to Dwellir support, either by email or on Telegram at [@dwellirgrowth](https://t.me/dwellirgrowth), and keep the old one running until the change is confirmed. With `try_new_peers` set to `false`, an unallowlisted node has nothing to fall back to and will stop syncing.

### Do you throttle the mempool stream?

No. You receive full gossip, the same stream Dwellir's own nodes consume.

### Is peering required to use Dwellir's Hyperliquid APIs?

No. The [gRPC streaming API](https://www.dwellir.com/docs/hyperliquid/grpc), [Order Book WebSocket](https://www.dwellir.com/docs/hyperliquid/order-book-server), and [Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint) all run on Dwellir infrastructure, and that infrastructure sits on the same peering backbone offered here.

Buy peering only if you run your own nodes and want more reliable peers. If you just want access to Hyperliquid data, use the Dwellir API platform or a [Dedicated Node Cluster](https://www.dwellir.com/docs/hyperliquid/pricing#dedicated-cluster) instead.

### Who do I contact?

Email [support@dwellir.com](mailto:support@dwellir.com?subject=Hyperliquid%20Peering), send a Telegram DM to [@dwellirgrowth](https://t.me/dwellirgrowth), or go through your existing Dwellir contact. Subscribers also get a shared Telegram or Slack Connect channel with the team.

---

## perpDexs - HyperCore Info Endpoint

# perpDexs - HyperCore Info Endpoint

Get all third-party perpetual DEXs deployed on Hyperliquid's infrastructure, including their listed assets, open interest caps, funding parameters, and deployer configuration.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `perpDexs` endpoint is essential for:

- **DEX Discovery** — Enumerate all perpetual DEXs deployed on Hyperliquid
- **Asset Listing** — Find which assets are available on each DEX and their open interest caps
- **Funding Analysis** — Query funding multipliers and interest rates across DEXs
- **Deployer Verification** — Verify deployer addresses and fee recipients for each DEX
- **Permission Auditing** — Inspect sub-deployer permissions and capabilities

## Request Parameters

- `type` (`string, required`): parameter: Must be `"perpDexs"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "perpDexs"
}'
```

## Response Fields

- `name` (`string, required`): Short identifier for the DEX (e.g., `"xyz"`, `"flx"`)
- `fullName` (`string, required`): Display name of the DEX (e.g., `"XYZ"`, `"Felix Exchange"`)
- `deployer` (`string, required`): Ethereum address of the DEX deployer
- `oracleUpdater` (`string | null, required`): Address authorized to update oracles, or `null`
- `feeRecipient` (`string | null, required`): Address that receives trading fees, or `null`
- `assetToStreamingOiCap` (`array, required`): List of `[assetName, capValue]` pairs
- `subDeployers` (`array, required`): List of `[permission, [addresses]]` pairs
- `deployerFeeScale` (`string, required`): Fee scale multiplier for the deployer
- `lastDeployerFeeScaleChangeTime` (`string, required`): ISO 8601 timestamp of last fee scale change
- `assetToFundingMultiplier` (`array, required`): List of `[assetName, multiplier]` pairs
- `assetToFundingInterestRate` (`array, required`): List of `[assetName, rate]` pairs

## Successful Response

```json
[
  null,
  {
    "name": "xyz",
    "fullName": "XYZ",
    "deployer": "0x88806a71d74ad0a510b350545c9ae490912f0888",
    "oracleUpdater": null,
    "feeRecipient": "0x9cd0a696c7cbb9d44de99268194cb08e5684e5fe",
    "assetToStreamingOiCap": [
      ["xyz:AAPL", "50000000.0"],
      ["xyz:GOLD", "500000000.0"],
      ["xyz:NVDA", "200000000.0"]
    ],
    "subDeployers": [
      ["registerAsset", ["0x7d16f116d252db609c56d27d6c9605eb03e16657"]],
      ["setOracle", ["0x1234567890545d1df9ee64b35fdd16966e08acec"]]
    ],
    "deployerFeeScale": "1.0",
    "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00",
    "assetToFundingMultiplier": [
      ["xyz:AAPL", "0.5"],
      ["xyz:GOLD", "0.5"]
    ],
    "assetToFundingInterestRate": []
  }
]
```

## Common Use Cases

### 1. List All DEXs and Their Assets

Enumerate all deployed DEXs with their asset counts and total OI capacity:

```javascript
async function listDexOverview() {
  const dexs = await getPerpDexs();

  console.log('=== Perpetual DEXs on Hyperliquid ===\n');
  dexs.filter(d => d !== null).forEach(dex => {
    const totalOiCap = dex.assetToStreamingOiCap.reduce(
      (sum, [, cap]) => sum + parseFloat(cap), 0
    );

    console.log(`${dex.fullName} (${dex.name})`);
    console.log(`  Deployer: ${dex.deployer}`);
    console.log(`  Assets: ${dex.assetToStreamingOiCap.length}`);
    console.log(`  Total OI Cap: $${(totalOiCap / 1e6).toFixed(1)}M`);
    console.log(`  Fee Scale: ${dex.deployerFeeScale}`);
    console.log('');
  });
}
```

### 2. Find a Specific Asset Across DEXs

Search for which DEXs list a specific asset:

```javascript
async function findAssetAcrossDexs(assetSymbol) {
  const dexs = await getPerpDexs();

  const results = [];
  dexs.filter(d => d !== null).forEach(dex => {
    const match = dex.assetToStreamingOiCap.find(
      ([name]) => name.split(':')[1] === assetSymbol
    );

    if (match) {
      const fundingEntry = dex.assetToFundingMultiplier.find(
        ([name]) => name === match[0]
      );

      results.push({
        dex: dex.fullName,
        dexPrefix: dex.name,
        asset: match[0],
        oiCap: match[1],
        fundingMultiplier: fundingEntry ? fundingEntry[1] : 'N/A'
      });
    }
  });

  console.log(`\n=== "${assetSymbol}" across DEXs ===\n`);
  results.forEach(r => {
    console.log(`${r.dex}: OI Cap $${(parseFloat(r.oiCap) / 1e6).toFixed(1)}M | Funding: ${r.fundingMultiplier}`);
  });

  return results;
}

// Usage
await findAssetAcrossDexs('GOLD');
```

### 3. Analyze Funding Parameters

Compare funding configurations across DEXs:

```javascript
async function analyzeFunding() {
  const dexs = await getPerpDexs();

  console.log('=== Funding Analysis ===\n');
  dexs.filter(d => d !== null).forEach(dex => {
    if (dex.assetToFundingMultiplier.length === 0 &&
        dex.assetToFundingInterestRate.length === 0) {
      console.log(`${dex.fullName}: No custom funding config`);
      return;
    }

    console.log(`${dex.fullName}:`);

    if (dex.assetToFundingMultiplier.length > 0) {
      const multipliers = dex.assetToFundingMultiplier.map(([, m]) => parseFloat(m));
      const avg = multipliers.reduce((a, b) => a + b, 0) / multipliers.length;
      console.log(`  Funding multipliers: ${multipliers.length} assets, avg ${avg.toFixed(4)}`);
    }

    if (dex.assetToFundingInterestRate.length > 0) {
      console.log(`  Interest rates: ${dex.assetToFundingInterestRate.length} assets`);
    }

    console.log('');
  });
}
```

### 4. Audit Sub-Deployer Permissions

Review which addresses have administrative permissions:

```javascript
async function auditPermissions(dexName) {
  const dexs = await getPerpDexs();
  const dex = dexs.find(d => d !== null && d.name === dexName);

  if (!dex) {
    console.log(`DEX "${dexName}" not found`);
    return;
  }

  console.log(`=== Permission Audit: ${dex.fullName} ===\n`);
  console.log(`Deployer: ${dex.deployer}`);
  console.log(`Oracle Updater: ${dex.oracleUpdater || 'None'}`);
  console.log(`Fee Recipient: ${dex.feeRecipient || 'None'}`);

  console.log('\nSub-Deployer Permissions:');
  dex.subDeployers.forEach(([permission, addresses]) => {
    console.log(`  ${permission}:`);
    addresses.forEach(addr => console.log(`    - ${addr}`));
  });
}

// Usage
await auditPermissions('xyz');
```

### 5. Monitor OI Cap Utilization

Build a dashboard showing available capacity:

```javascript
async function getOiCapSummary() {
  const dexs = await getPerpDexs();

  const summary = dexs
    .filter(d => d !== null)
    .map(dex => {
      const assets = dex.assetToStreamingOiCap.map(([name, cap]) => ({
        asset: name,
        oiCap: parseFloat(cap)
      }));

      const totalCap = assets.reduce((sum, a) => sum + a.oiCap, 0);
      const topAssets = assets
        .sort((a, b) => b.oiCap - a.oiCap)
        .slice(0, 3);

      return {
        name: dex.fullName,
        assetCount: assets.length,
        totalOiCap: totalCap,
        topAssets: topAssets
      };
    })
    .sort((a, b) => b.totalOiCap - a.totalOiCap);

  console.log('=== OI Cap Summary (by total capacity) ===\n');
  summary.forEach(dex => {
    console.log(`${dex.name}: $${(dex.totalOiCap / 1e6).toFixed(0)}M total (${dex.assetCount} assets)`);
    dex.topAssets.forEach(a => {
      console.log(`  ${a.asset}: $${(a.oiCap / 1e6).toFixed(0)}M`);
    });
    console.log('');
  });

  return summary;
}
```

## Best Practices

1. **Filter null entries** — The response array may contain `null` values at certain indices
2. **Cache results** — DEX configurations change infrequently, cache for 5-15 minutes
3. **Parse asset names** — Asset names use the format `dexName:SYMBOL` (e.g., `"xyz:GOLD"`)
4. **Monitor fee changes** — Check `lastDeployerFeeScaleChangeTime` for recent fee updates
5. **Validate deployer addresses** — Verify deployer and fee recipient addresses when integrating

## Related Endpoints

- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get core Hyperliquid trading pair metadata
- [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta) — Get spot trading asset metadata
- [**exchangeStatus**](https://www.dwellir.com/docs/hyperliquid/exchange-status) — Monitor exchange health and status
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state for a specific DEX or use `ALL_DEXES` to aggregate across all operational DEXs
- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state) — Combine `ALL_DEXES` perp state with spot balances and account mode
- [**candles**](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles#discovering-markets) — Use `prefix:ASSET` symbols as the `market` parameter for candle queries

***

*Discover perpetual DEXs on Hyperliquid with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## perpDeploy payload - Perpetual Market Deployment

# perpDeploy payload - Perpetual Market Deployment

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `perpDeploy` payload records a perpetual-market deployment or oracle-configuration update.

## Sample Data

```json
{
  "signature": {
    "r": "0xf07b23ce4dbff09a3b0b3c2036842b2430c9fc3b997a4cf45ba3a4d5e7b1d025",
    "s": "0x37991b945e9ac813aa278df339c85e22a9bd395107adf21b1ac0ac7d41efcfa3",
    "v": 27
  },
  "action": {
    "type": "perpDeploy",
    "setFundingMultipliers": [
      ["vntl:ANTHROPIC", "0.003000000118"],
      ["vntl:OPENAI", "0.00300303706"],
      ["vntl:SPACEX", "0.003000000026"]
    ]
  },
  "nonce": 1768146962347
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x3bbd5fc75c2f55a93d37043326474302015b00acf722747bdf860b1a1b232f93)

## Field Reference

### Action Fields

| Field                   | Type   | Description                               |
| ----------------------- | ------ | ----------------------------------------- |
| `type`                  | string | Always `"perpDeploy"`                     |
| `setFundingMultipliers` | array  | Funding rate multipliers per market       |
| `setOracle`             | object | Oracle price configurations (alternative) |

## Use Cases

### Market Configuration Tracking

Monitor market deployments and updates:

```python
def process_perpDeploy_action(action):
    if 'setFundingMultipliers' in action:
        markets = action['setFundingMultipliers']
        print(f"Funding updated for {len(markets)} markets")
```

## Related Action Payloads

- [multiSig](https://www.dwellir.com/docs/hyperliquid/multiSig) - Often wrapped in multi-sig for governance

---

## portfolioState - HyperCore Info Endpoint

# portfolioState - HyperCore Info Endpoint

Get perpetual clearinghouse state, spot balances, and account abstraction mode for a single user in one request.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `portfolioState` endpoint is useful when you need a full portfolio view without coordinating multiple requests yourself.

- **Portfolio Dashboards** — Load perp state, spot balances, and account mode in one round trip
- **Risk Systems** — Combine derivative exposure with spot collateral and account abstraction mode
- **Wallet Experiences** — Build one portfolio summary card from a single response
- **Multi-DEX Views** — Use `dex: "ALL_DEXES"` to inspect the native DEX and all operational HIP-3 DEXs together

## Request Parameters

- `type` (`string, required`): parameter: Must be "`portfolioState`"
- `user` (`string, required`): parameter: User's Ethereum wallet address
- `dex` (`string, optional`): parameter: HIP-3 market identifier. Query "`perpDexs`" first to discover supported DEX names. Omit to query the main Hyperliquid DEX, or use "`ALL_DEXES`" to aggregate the main DEX plus all operational HIP-3 DEXs.

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "portfolioState",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `clearinghouseState` (`object, required`): Perpetual clearinghouse state. Native or named DEX queries return the regular clearinghouseState object; "`ALL_DEXES`" returns an object keyed by DEX name.
- `spotClearinghouseState` (`object, required`): Spot balances object containing a "`balances`" array for the user.
- `spotClearinghouseState.balances` (`array, required`): Token balance objects with "`coin`", "`token`", "`total`", "`hold`", and "`entryNtl`".
- `userAbstraction` (`string, required`): Account abstraction mode such as "`default`", "`unifiedAccount`", "`portfolioMargin`", "`disabled`", or "`dexAbstraction`".

## Successful Response

```json
{
  "clearinghouseState": {
    "marginSummary": {
      "accountValue": "555.13644",
      "totalMarginUsed": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "555.13644"
    },
    "crossMarginSummary": {
      "accountValue": "555.13644",
      "totalMarginUsed": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "555.13644"
    },
    "crossMaintenanceMarginUsed": "0.0",
    "withdrawable": "555.13644",
    "assetPositions": [],
    "time": 1776448114752
  },
  "spotClearinghouseState": {
    "balances": [
      {
        "coin": "USDC",
        "token": 0,
        "total": "12.27568764",
        "hold": "0.0",
        "entryNtl": "0.0"
      }
    ]
  },
  "userAbstraction": "default"
}
```

## The `dex` Parameter

By default, `portfolioState` returns the main Hyperliquid perpetuals DEX state, spot balances, and account abstraction mode for a single user. To target a specific HIP-3 market, pass a DEX name returned by [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs). To aggregate across the native DEX and all operational HIP-3 markets, use `dex: "ALL_DEXES"`.

| `dex` value                                                                      | Returns                                                                                                                            |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| *(omitted)*                                                                      | Native Hyperliquid perp state plus spot balances and account mode                                                                  |
| Any DEX name returned by [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs) | The named HIP-3 DEX state plus spot balances and account mode                                                                      |
| `"ALL_DEXES"`                                                                    | A DEX map of perp state for the native DEX plus every operational HIP-3 market, alongside top-level spot balances and account mode |

### `ALL_DEXES` Request

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "portfolioState",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f",
  "dex": "ALL_DEXES"
}'
```

### `ALL_DEXES` Response Shape

```json
{
  "clearinghouseState": {
    "native": {
      "marginSummary": {
        "accountValue": "555.13644",
        "totalMarginUsed": "0.0",
        "totalNtlPos": "0.0",
        "totalRawUsd": "555.13644"
      },
      "crossMarginSummary": {
        "accountValue": "555.13644",
        "totalMarginUsed": "0.0",
        "totalNtlPos": "0.0",
        "totalRawUsd": "555.13644"
      },
      "crossMaintenanceMarginUsed": "0.0",
      "withdrawable": "555.13644",
      "assetPositions": [],
      "time": 1776448114752
    },
    "<dex_name>": {
      "marginSummary": {
        "accountValue": "0.0",
        "totalMarginUsed": "0.0",
        "totalNtlPos": "0.0",
        "totalRawUsd": "0.0"
      },
      "crossMarginSummary": {
        "accountValue": "0.0",
        "totalMarginUsed": "0.0",
        "totalNtlPos": "0.0",
        "totalRawUsd": "0.0"
      },
      "crossMaintenanceMarginUsed": "0.0",
      "withdrawable": "0.0",
      "assetPositions": [],
      "time": 1776448114649
    }
  },
  "spotClearinghouseState": {
    "balances": [
      {
        "coin": "USDC",
        "token": 0,
        "total": "12.27568764",
        "hold": "0.0",
        "entryNtl": "0.0"
      }
    ]
  },
  "userAbstraction": "default"
}
```

For `ALL_DEXES`, `clearinghouseState` becomes an object keyed by DEX name while `spotClearinghouseState` and `userAbstraction` remain at the top level. The native DEX always appears under the `"native"` key. Additional keys are dynamic and correspond to operational HIP-3 DEX names returned by [`perpDexs`](https://www.dwellir.com/docs/hyperliquid/perp-dexs), so discover them instead of hardcoding a single example value.

## What `portfolioState` Composes

`portfolioState` is equivalent to combining these three requests:

- [`clearinghouseState`](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — perp positions and margin data
- [`spotClearinghouseState`](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — spot balances
- [`userAbstraction`](https://www.dwellir.com/docs/hyperliquid/user-abstraction) — account abstraction mode

When `dex` is `"ALL_DEXES"`, the endpoint reuses the `ALL_DEXES` clearinghouse aggregation and keeps the spot and abstraction data at the top level.

## Billing

`portfolioState` is billed by the number of upstream responses it aggregates, not as one response per HTTP request.

- `{"type":"portfolioState","user":"0x63E8c7C149556D5f34F833419A287bb9Ef81487f"}` counts as `3` responses/API credits.
- `{"type":"portfolioState","user":"0x63E8c7C149556D5f34F833419A287bb9Ef81487f","dex":"xyz"}` counts as `3` responses/API credits.
- `{"type":"portfolioState","user":"0x63E8c7C149556D5f34F833419A287bb9Ef81487f","dex":"ALL_DEXES"}` counts as `N + 3` responses/API credits, where `N` is the number of keys in the returned `clearinghouseState` map, including `"native"`. For example, `10` returned DEX keys count as `13` responses/API credits.

DEX discovery counts even when served from the gateway cache. Non-success HTTP responses are not charged.

## Common Use Cases

### 1. Build a Portfolio Overview

```javascript
async function getPortfolioOverview(userAddress) {
  const response = await fetch('https://api-hyperliquid-mainnet-info.n.dwellir.com/<API-KEY>/info', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      type: 'portfolioState',
      user: userAddress,
      dex: 'ALL_DEXES'
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }

  const portfolio = await response.json();
  return {
    abstraction: portfolio.userAbstraction,
    perpDexes: Object.keys(portfolio.clearinghouseState),
    spotBalances: portfolio.spotClearinghouseState.balances.length
  };
}
```

### 2. Merge Spot and Perp State for UI Rendering

```javascript
async function getDashboardState(userAddress) {
  const portfolio = await queryEndpoint({
    type: 'portfolioState',
    user: userAddress
  });

  return {
    accountValue: parseFloat(portfolio.clearinghouseState.marginSummary.accountValue),
    withdrawable: parseFloat(portfolio.clearinghouseState.withdrawable),
    balances: portfolio.spotClearinghouseState.balances,
    accountMode: portfolio.userAbstraction
  };
}
```

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get perpetual account state, including `ALL_DEXES` support
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot account balances
- [**userAbstraction**](https://www.dwellir.com/docs/hyperliquid/user-abstraction) — Get account abstraction mode only
- [**batchPortfolioState**](https://www.dwellir.com/docs/hyperliquid/batch-portfolio-state): Batch query perp state, spot balances, and account mode for multiple users
- [**batchClearinghouseStates**](https://www.dwellir.com/docs/hyperliquid/batch-clearinghouse-states) — Batch query multiple users

***

*Query full Hyperliquid portfolio state with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## Hyperliquid Pricing

# Hyperliquid Pricing

Dwellir offers HyperEVM smart contract access and HyperCore trading data. Choose an API plan with metered add-ons on the shared cluster, or your own Dedicated Node Cluster. The [Hyperliquid API docs](https://www.dwellir.com/docs/hyperliquid) cover every endpoint these plans give you.

This page covers Dwellir's infrastructure pricing. For Hyperliquid's own trading fees, including maker and taker tiers, HYPE staking discounts, HIP-3 and builder fees, see [Hyperliquid fees explained](https://www.dwellir.com/blog/hyperliquid-fees-explained).

| Option                 | Monthly price                   | Infrastructure                        | gRPC and Order Book add-ons |
| ---------------------- | ------------------------------- | ------------------------------------- | --------------------------- |
| Metered gRPC           | $299 + usage                    | Shared cluster                        | gRPC only                   |
| Metered Order Book     | $199 + usage                    | Shared cluster                        | Order Book only             |
| Dedicated Node Cluster | Starts at $4,000, no usage fees | Starts with 2 dedicated backend nodes | Both included and unmetered |

Metered add-ons need an API plan. Each streamed message costs 1 API credit, and usage above the plan's included credits is billed per million at the plan's overage rate. The Dedicated Node Cluster, from $4,000/month, includes both add-ons, HyperEVM JSON-RPC, and Info endpoints.

## HyperCore and HyperEVM coverage

HyperEVM serves Ethereum-compatible smart contracts through JSON-RPC. HyperCore contains the trading engine, order books, fills, and positions. An EVM RPC endpoint alone does not provide HyperCore gRPC or Order Book streams.

Dwellir supports both layers. Compare providers by the exact endpoint and data service included in their quote, alongside shared or dedicated infrastructure.

[Chainstack's Hyperliquid guide](https://chainstack.com/learn/how-to/how-to-get-hyperliquid-rpc-endpoint-perps-2026/) advertises HyperEVM and HyperCore access. [QuickNode's API overview](https://www.quicknode.com/docs/hyperliquid/api-overview) also lists both layers, including gRPC streams. Confirm the required feed and add-on coverage for each quoted product.

## Service Tiers

### gRPC Streaming API

High-performance real-time streaming for order books, blocks, trades, and fills.

**$299/month + usage** as a standalone service; **included with a Dedicated Node Cluster**

- Real-time block streaming
- Trade and fill notifications
- Order book snapshots
- WebSocket connections
- Production-grade reliability
- Dedicated support

**Usage charges** (standalone): Billed monthly based on API credits consumed (1 response = 1 credit)

A [Dedicated Node Cluster](#dedicated-cluster) includes gRPC and Order Book access from $4,000/month, with no separate add-on fees and no usage charges.

Get gRPC Access

***

### Order Book Server

Low-latency WebSocket API for real-time order book data and market updates.

**$199/month + usage** as a standalone service; **included with a Dedicated Node Cluster**

- WebSocket order book streams (L2 aggregated depth or L4 individual orders)
- Real-time market data from Singapore & Tokyo edge servers
- Trade execution feeds
- Optimized for trading bots
- Sub-millisecond updates (one message per block, \~13 messages/sec per pair)
- High availability

**Usage charges** (standalone): Billed monthly based on API credits consumed (1 response = 1 credit)

Use our [**Volume Calculator**](https://www.dwellir.com/hyperliquid-orderbook#calculator) to estimate your monthly message volume based on trading pairs and depth levels.

Learn More & Calculate Pricing

***

### Peering

Reserved gossip peer slots for a Hyperliquid node you run yourself.

**$500/month flat**, per peering slot (no usage or egress charges). A peering slot allowlists one of your node IPs on Dwellir's peering infrastructure.

- Your node IP reserved on 3 Dwellir peers, single region
- Full gossip, including the full mempool
- 99.9% monthly uptime SLA
- Open access with published, non-discriminatory pricing

Peering makes **your** node more reliable. If you want Dwellir to run the node and the data services, choose a [Dedicated Node Cluster](#dedicated-cluster). See the [Peering documentation](https://www.dwellir.com/docs/hyperliquid/peering) for setup steps and requirements.

Request Peering Access

***

### Dedicated Node Cluster

Your own isolated Hyperliquid backends for HyperEVM and HyperCore, starting with 2 nodes.

**Starts at $4,000/month** (unmetered, no usage fees)

- Starts with 2 dedicated backend nodes serving HyperEVM and HyperCore
- Uncapped throughput within your cluster's capacity
- **Unmetered billing** - Flat monthly rate, no usage charges
- Isolated infrastructure
- **Info endpoints included** at no extra cost
- [gRPC Streaming API](https://www.dwellir.com/docs/hyperliquid/grpc) add-on included and unmetered, with no separate $299 fee
- [Order Book Server](https://www.dwellir.com/docs/hyperliquid/order-book-server) add-on included and unmetered, with no separate $199 fee
- Extended SLAs available
- Priority support
- Custom configurations available

When a cluster pays off over shared endpoints is covered in [Hyperliquid Dedicated Node Clusters: performance, reliability, and when to upgrade](https://www.dwellir.com/blog/hyperliquid-dedicated-node-clusters).

Request Dedicated Node Cluster

***

### Historical Data Access

#### Archival Fills Data

Complete historical trade fill data for backtesting and analysis.

**Custom pricing** - Contact us for details

- Full trade history
- Fill-level granularity
- Bulk data exports
- Optimized for analytics
- Flexible delivery formats

Request Fills Data

#### Archival Replica Commands Data

Historical command and state data for comprehensive chain analysis.

**Custom pricing** - Contact us for details

- Complete command history
- State snapshots
- Chain replay capability
- Bulk data access
- Research-grade datasets

Request Replica Data

***

## Usage-Based Billing

### Standalone Services (gRPC API, Order Book Server)

For metered gRPC and Order Book subscriptions, usage is billed monthly alongside the add-on fee. A [Dedicated Node Cluster](#dedicated-cluster) removes usage charges.

#### Simple Credit Model

- **1 API response = 1 credit**
- No complex compute unit calculations
- Transparent and predictable costs
- Real-time usage tracking in dashboard

#### Standard Usage Rates

Usage beyond the base subscription is billed at the following rates:

| Plan Tier         | Rate per Million Credits                              |
| ----------------- | ----------------------------------------------------- |
| gRPC API          | See [standard pricing](https://www.dwellir.com/docs/getting-started/pricing) |
| Order Book Server | See [standard pricing](https://www.dwellir.com/docs/getting-started/pricing) |

For high-volume users, custom volume discounts are available.

### Dedicated Node Cluster (Unmetered)

**Dedicated Node Cluster subscriptions are completely unmetered:**

- **Flat monthly pricing** - No usage charges ever
- **Unlimited RPS** - Make as many requests as your nodes can handle
- **Info endpoints included** - Free with every Dedicated Node Cluster
- **No rate limits** - Scale to your application's needs

| Component                                                    | Monthly Cost |
| ------------------------------------------------------------ | ------------ |
| Dedicated Node Cluster (JSON-RPC + Info + gRPC + Order Book) | From $4,000  |

Choose a Dedicated Node Cluster if you:

- Need dedicated backends, starting with 2 nodes
- Require infrastructure isolation or custom configurations
- Want gRPC, Order Book, HyperEVM JSON-RPC, and Info bundled together

***

## Enterprise Solutions

For institutional traders, market makers, and high-frequency trading firms requiring custom infrastructure:

**Custom pricing** based on your needs

### Enterprise Features

- Custom SLA agreements
- Multi-region deployment
- Dedicated infrastructure
- Direct engineering support
- Custom data feeds
- Volume discounts
- Flexible payment terms
- Priority feature requests

Contact Sales

***

## Comparison Table

| Feature               | gRPC API                                              | Order Book Server                                     | Peering                  | Dedicated Node Cluster  | Enterprise |
| --------------------- | ----------------------------------------------------- | ----------------------------------------------------- | ------------------------ | ----------------------- | ---------- |
| **Base Price**        | $299/mo + usage                                       | $199/mo + usage                                       | $500/mo per peering slot | From $4,000/mo          | Custom     |
| **You run the node**  | No                                                    | No                                                    | **Yes**                  | No                      | Custom     |
| **gRPC Streaming**    | Standalone service                                    | Not included                                          | Not included             | **Included**            | Custom     |
| **Order Book Server** | Not included                                          | Standalone service                                    | Not included             | **Included**            | Custom     |
| **Info Endpoints**    | See [standard pricing](https://www.dwellir.com/docs/getting-started/pricing) | See [standard pricing](https://www.dwellir.com/docs/getting-started/pricing) | Not included             | **Included**            | Custom     |
| **Usage Billing**     | Metered                                               | Metered                                               | **Unmetered**            | **Unmetered**           | Custom     |
| **Request Limits**    | Rate limited                                          | Rate limited                                          | n/a                      | Within cluster capacity | Custom     |
| **Uptime SLA**        | Standard                                              | Standard                                              | **99.9%**                | Extended available      | Custom     |

***

## Getting Started

1. **Choose your tier** - Select the service that matches your trading needs
2. **Contact us** - Reach out via email to set up your account
3. **Get credentials** - Receive your API keys and endpoint URLs
4. **Start building** - Integrate with our comprehensive documentation
5. **Scale seamlessly** - Upgrade anytime as your needs grow

### Questions About Pricing?

Our team is happy to help you choose the right plan for your use case:

- **Email**: <support@dwellir.com>
- **Documentation**: [Hyperliquid Docs](https://www.dwellir.com/docs/hyperliquid)
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

## Frequently Asked Questions

### How is usage calculated?

**For standalone services** (gRPC API and Order Book Server), usage is calculated based on API credits consumed. Each API response counts as 1 credit. Usage is tracked in real-time and displayed in your dashboard.

**For Dedicated Node Clusters**, there is no usage calculation or metering. You pay a flat monthly rate with completely unlimited usage. gRPC streaming and the Order Book Server are included and unmetered.

### Does the Dedicated Node Cluster include add-ons?

Yes. The cluster starts at $4,000/month and includes unmetered gRPC and Order Book access with no separate add-on fees. HyperEVM JSON-RPC, Info endpoints, and your own backends, starting with 2 nodes, are also included.

### Can I switch between tiers?

Yes! You can upgrade or downgrade your service tier at any time. Changes take effect at the next billing cycle, and we'll help with any migration needed.

### What payment methods do you accept?

We accept credit/debit cards, bank transfers, and cryptocurrency. Crypto payment is available on every paid plan, add-on, and dedicated cluster. Enterprise customers can also negotiate custom payment terms.

### Is there a free trial?

Contact our sales team to discuss trial options for your specific use case. We're happy to provide demo access to evaluate our infrastructure.

### What happens if I exceed my usage limits?

**For metered standalone services**, usage beyond your plan's allocation is automatically billed at the end of the month at the per-credit rate. You can set spending limits in your dashboard to prevent unexpected charges.

**For Dedicated Node Clusters**, included services have no usage charges. Throughput depends on your cluster's capacity.

### Do you offer volume discounts?

Yes! High-volume users and enterprise customers can negotiate volume discounts. Contact our sales team to discuss custom pricing.

***

*Need help choosing the right plan? [Contact our team](mailto:support@dwellir.com) for personalized recommendations.*

---

## registerReferrer payload - Referrer Registration

# registerReferrer payload - Referrer Registration

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `registerReferrer` payload records registration of a referral code for a Hyperliquid account.

## Sample Data

```json
{
  "signature": {
    "r": "0xcb7c3ba391ec86d5ca0f6a3bc9b9d5f2f5926ed387de53c66a38d0a518f5c220",
    "s": "0x728624e01619451fb16400a8393e25c6ec663adfb498ce9d73145f726766e322",
    "v": 27
  },
  "action": {
    "type": "registerReferrer",
    "code": "LV88"
  },
  "nonce": 1767949731159
}
```

## Field Reference

### Action Fields

| Field  | Type   | Description                 |
| ------ | ------ | --------------------------- |
| `type` | string | Always `"registerReferrer"` |
| `code` | string | Referral code to register   |

## Use Cases

### Referrer Registration Tracking

Monitor new referrer registrations:

```python
def process_registerReferrer_action(action):
    code = action.get('code')
    print(f"New referrer registered: {code}")
```

## Related Action Payloads

- [setReferrer](https://www.dwellir.com/docs/hyperliquid/setReferrer) - Referrer assignments
- [claimRewards](https://www.dwellir.com/docs/hyperliquid/claimRewards) - Referral reward claims

---

## Hyperliquid archive research and validation

# Hyperliquid archive research and validation

Choose the inputs that answer your research question. Validate their range and schema before treating the files as a complete dataset.

## Which files answer my question?

| Research question                                        | Required inputs                                                                                                                                                                                                   |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Individual executions and fees                           | [Fills](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/fills)                                                                                                                                                          |
| TWAP lifecycle and execution slices                      | [TWAP statuses](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/twap-statuses) plus fills                                                                                                                               |
| TWAP submissions, cancellations, and execution responses | [Blocks](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks), including signed actions and responses                                                                                                                |
| Orders that cancel or reject without fills               | [Order statuses](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/order-statuses), with blocks for action-level analysis                                                                                                 |
| Reconstruct an order book                                | [Generated snapshot](https://www.dwellir.com/docs/hyperliquid/data-catalog/derived/book-snapshots) plus ordered [raw book diffs](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/book-diffs)                                                   |
| Native node state at a checkpoint                        | [Periodic ABCI state](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/abci-states), with a matching binary decoder                                                                                                      |
| Applied mark or oracle prices at a past block            | Periodic ABCI state plus `replica_cmds` [blocks](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/blocks), replayed with a Hyperliquid node. See [historical mark prices](#can-i-get-every-historical-mark-price-update) |

A fills-only sample excludes orders that never execute. A TWAP created before your selection can execute inside it without an in-range creation event.

Use an earlier state seed or earlier lifecycle records when your analysis needs activity already in progress at the start.

## How do I define the range and download size?

Specify the feed prefixes and UTC bounds. Use an inclusive start and exclusive end to avoid overlapping adjacent selections.

For September 2026, select `2026-09-01T00:00:00Z` through, but excluding, `2026-10-01T00:00:00Z`.

Hourly files can contain records outside a partial-hour selection. Filter records by the relevant event or block timestamp after decompression.

Use the [archive coverage table and size estimator](https://www.dwellir.com/docs/hyperliquid/historical-data#compressed-size-and-file-count) to plan compressed storage and downloads before purchase.

File count does not establish record count or completeness. Do not assume one file per hour or infer missing events from object totals alone.

## What should a validation manifest contain?

Record these fields for each selection:

| Field                                          | Purpose                                                     |
| ---------------------------------------------- | ----------------------------------------------------------- |
| Feed, object key, and format                   | Select the correct parser and identify each file.           |
| Compressed bytes per object and combined total | Verify download volume.                                     |
| File count and listing time in UTC             | Reproduce the inventory measurement.                        |
| First and last record positions                | Check actual record bounds against the requested selection. |
| Checksum value and algorithm                   | Verify transferred bytes.                                   |
| Schema or decoder version                      | Reproduce decoding, especially for binary state.            |
| Known gaps, overlaps, and backfilled intervals | Separate stored coverage from verified completeness.        |

An [S3 ETag](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Object.html) is not always an MD5 checksum. Compare checksums calculated with the same algorithm.

Decompress each file and parse every record. Check ordering and duplicates using the feed's sequential position and event identity.

Some filtered feeds omit blocks with no matching events. A jump in those positions alone does not prove missing source data.

Treat an unverified interval as unverified. The [coverage table](https://www.dwellir.com/docs/hyperliquid/historical-data#s3-bucket-coverage) gives date bounds, not a completeness certificate.

## Which timestamp should I use?

| Field                  | Meaning                                                                                        |
| ---------------------- | ---------------------------------------------------------------------------------------------- |
| Envelope `block_time`  | The source block timestamp.                                                                    |
| Envelope `local_time`  | The source record's local wall-clock timestamp. It is not your application's receipt time.     |
| Fill `time`            | Execution time in Unix milliseconds.                                                           |
| TWAP `state.timestamp` | TWAP creation time in Unix milliseconds.                                                       |
| V3 `Record.timestamp`  | Transport cursor in Unix milliseconds. Use the method's documented source timestamp semantics. |

Native timestamp strings can omit the trailing `Z`. Parse the documented source layout as UTC rather than your machine's local timezone.

Preserve nanosecond precision when source strings provide it. Do not interpret Unix milliseconds as seconds.

Replaying a record does not establish when a client originally received it. S3 modification time also does not establish event time or live arrival latency.

## How do I join TWAP lifecycle events to executions?

Join lifecycle `twap_id` to the fill payload's `twapId`. Retain the account and market alongside the identifier when validating the join.

The fill's `oid` identifies a child order. It does not replace the parent TWAP identifier.

`state.executedSz` and `state.executedNtl` describe aggregate execution at a lifecycle boundary. They are not a continuously sampled progress series.

Use fills to calculate executions between lifecycle events. Preserve partial, cancelled, and zero-fill orders when the available lifecycle or action records identify them.

The status feed is not a complete log of every TWAP submission attempt. Decode `twapOrder` and `twapCancel` from blocks and inspect their execution responses.

The documented TWAP action has duration, size, side, reduce-only, and randomization fields. It does not contain a `stopPx` trigger field.

For account queries, use [TWAP slice fills](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/fills/user-twap-slice-fills). Fills-derived summaries cannot establish a complete zero-fill population.

## How do I identify the liquidated side of a trade?

Inspect the fill's optional `liquidation` object. It includes `liquidatedUser`, `markPx`, and `method`.

Counterparty fills can carry liquidation metadata too. Match the event's account to `liquidatedUser` to identify the liquidated side.

For book-absorbed liquidations, `crossed: true` identifies the liquidated taker side. Do not require that flag to classify every liquidation method.

Keep the source method value, including `market` or `backstop`. Do not classify every close as a liquidation or infer auto-deleveraging from `dir` alone.

Within one block, group a trade match by `(coin, tid)`. Across blocks, include `block_number` or `block_time` in the match key.

Hyperliquid documents `(block_time, coin, tid)` as the [globally unique trade identity](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions).
Preserve separate account and order records because one match can include several makers.

See [the fill schema and liquidation rules](https://www.dwellir.com/docs/hyperliquid/stream_fills#liquidation-data) for field details.

## Can I get every historical mark-price update?

No archive prefix stores mark or oracle prices as their own records. Hyperliquid applies them inside node state, and the node does not write them to a separate file.

To get the applied values at a past block, start a Hyperliquid node from a [periodic ABCI state](https://www.dwellir.com/docs/hyperliquid/data-catalog/node-feeds/abci-states) checkpoint. Then replay the `replica_cmds` blocks that follow it. ABCI state coverage starts on `2026-04-14`, so earlier blocks have no checkpoint to start from.

Validator oracle submissions appear in `replica_cmds` as [`SetGlobalAction`](https://www.dwellir.com/docs/hyperliquid/SetGlobalAction) payloads. These are inputs, not the mark price that the protocol applied.

HIP-3 deployers submit `oraclePxs` and `markPxs` for their own perp dexes through the `setOracle` field of [`perpDeploy`](https://www.dwellir.com/docs/hyperliquid/perpDeploy) actions. Every `setOracle` in the 2026-10-21 sample names a HIP-3 dex (`io` or `xyz`). These are inputs too, not applied mark prices.

To check which prefix holds a field, see "Observed fields" on each [data catalog](https://www.dwellir.com/docs/hyperliquid/data-catalog) page. Each tree lists the fields seen in one real archive object.

[`StreamActiveAssetCtx`](https://www.dwellir.com/docs/hyperliquid/stream_active_asset_ctx) reports live `mark_px` and `oracle_px`. It has no historical replay and drops obsolete frames when a subscriber lags. Its `time` is the endpoint update time, not a block timestamp. A recording of this stream is therefore not a complete, block-numbered update log.

A liquidation fill carries `markPx` in its `liquidation` object. That value applies to that liquidation only.

## Can I reconstruct account risk from book snapshots?

No. A generated order-book snapshot contains book state. It does not contain a complete account ledger or margin state.

Fills alone do not establish deposits, withdrawals, funding, transfers, collateral, or every state transition that affects account risk.

Periodic ABCI state is binary RMP, encoded with MessagePack. Decompress LZ4 first, then use a decoder that matches the source node-state schema.

An arbitrary requested timestamp can fall between snapshots. Reaching that state requires the earlier checkpoint and the intervening protocol transitions.

Use the node-state schema and asset mappings from that period. Account-risk replay also needs the protocol transitions after the checkpoint.

For current account state, use [clearinghouseState](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) and related Info methods. Current responses do not reconstruct past account state.

## May I store, redistribute, or sell the data?

This section summarizes the [Terms of Service](https://www.dwellir.com/terms-of-service). If the docs and Terms differ, the legally binding Terms control.

The [Terms of Service](https://www.dwellir.com/terms-of-service) permit storage, commercial use, distribution, and sale of Service Data and derived products.

They also permit resale through infrastructure you control. Keep Dwellir-issued credentials private and remain responsible for account usage and limits.

These permissions do not override third-party rights. After service termination, you may retain and commercialize data lawfully retrieved beforehand, subject to the terms.

---

## reserveRequestWeight payload - Request Weight Reservations

# reserveRequestWeight payload - Request Weight Reservations

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `reserveRequestWeight` payload records a request-capacity reservation in Hyperliquid's control plane.

## How to Read It

Unlike trading or transfer actions, the payload here is intentionally compact: the action body only carries the requested `weight`. Signature, nonce, and execution status come from the surrounding signed-action envelope and the paired response entry.

## Sample Data

```json
{
  "signature": {
    "r": "0x3eab58f491988095343c3391ac498fcc8803a3692c0c3047c8f56088ab8589ea",
    "s": "0xd59535932e8490a63d90d70071f033bd0b59fb4025aa5a57a65b8af57ea71ff",
    "v": 27
  },
  "action": {
    "type": "reserveRequestWeight",
    "weight": 5000
  },
  "nonce": 1767951014393
}
```

## Field Reference

### Envelope Fields

| Field       | Type   | Description                                              |
| ----------- | ------ | -------------------------------------------------------- |
| `signature` | object | ECDSA signature for the signed action                    |
| `nonce`     | number | Replay-protection nonce used for ordering and uniqueness |

### Action Fields

| Field    | Type   | Description                     |
| -------- | ------ | ------------------------------- |
| `type`   | string | Always `"reserveRequestWeight"` |
| `weight` | number | Request weight to reserve       |

## Processing Guidance

- Treat this as a system or workflow signal rather than a user-visible balance change.
- Preserve the nonce and bundle ordering when indexing it. These actions are often most useful when analyzed in sequence with the actions that follow.
- Confirm execution with the paired response status before assuming the reservation succeeded.
- If your analytics focus on economic activity, classify this separately from trade, transfer, and collateral actions so it does not distort volume metrics.

## Common Use Cases

### Automation Observability

Track these actions to understand when bots, agents, or infrastructure workflows reserve capacity before a burst of subsequent activity.

### Control-Plane Filtering

Separate request-weight reservations from user-facing actions when building dashboards or compliance summaries.

## Related Action Payloads

- [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) for block and response pairing

---

## scheduleCancel payload - Scheduled Cancellations

# scheduleCancel payload - Scheduled Cancellations

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `scheduleCancel` payload records creation, extension, or removal of Hyperliquid's scheduled cancel-all operation.

## Sample Data

```json
{
  "signature": {
    "r": "0x716e2f7591f552ba784c39fa3198c71a83fc13d93d206aa650571206149cb747",
    "s": "0x6e021299550e2b71871f3e98acf02c45c4fe5c0a09b4fc1e613db585eb9d0150",
    "v": 28
  },
  "action": {
    "type": "scheduleCancel",
    "time": 1768146928010
  },
  "nonce": 1768146913010
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x6af694b1b999c8a06c7004332644bd0201680097549ce7720ebf4004789da28b)

## Field Reference

### Action Fields

| Field  | Type   | Description                                                  |
| ------ | ------ | ------------------------------------------------------------ |
| `type` | string | Always `"scheduleCancel"`                                    |
| `time` | number | UTC timestamp (milliseconds) when orders should be cancelled |

## Dead-Man's Switch Pattern

The native scheduled-cancellation flow typically works as follows:

1. A client submits orders and schedules cancellation for T+N seconds through Hyperliquid's native Exchange API.
2. The client continuously extends the cancellation time while operating normally.
3. If the client fails, Hyperliquid cancels the orders at the scheduled time.

This prevents orphaned orders from remaining on the book if a trading bot crashes.

## Use Cases

### Risk Management Monitoring

Track how traders implement fail-safes:

```python
def process_scheduleCancel_action(action):
    cancel_time = action.get('time')
    if cancel_time:
        from datetime import datetime
        cancel_dt = datetime.fromtimestamp(cancel_time / 1000)
        print(f"Orders scheduled to cancel at {cancel_dt}")
```

### Bot Health Detection

Monitor schedule cancel extensions as a proxy for bot health.

### Market Stability Analysis

Track how many orders have dead-man switches configured.

## Related Action Payloads

- [order](https://www.dwellir.com/docs/hyperliquid/order) - Order payloads
- [cancel](https://www.dwellir.com/docs/hyperliquid/cancel) - Immediate order cancellation
- [cancelByCloid](https://www.dwellir.com/docs/hyperliquid/cancelByCloid) - Cancellations by client order ID

---

## sendAsset payload - Asset Transfers

# sendAsset payload - Asset Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `sendAsset` payload records an asset transfer with flexible source, destination, and cross-DEX fields.

## Sample Data

```json
{
  "signature": {
    "r": "0x93eef9b0e03606c293b12d43930c38dc246777cb222b3eb296396bc46d9481b5",
    "s": "0x295978b118626247150483ce4c462680dcaa8ba4cf1f9cc779967d8503287900",
    "v": 28
  },
  "action": {
    "type": "sendAsset",
    "signatureChainId": "0x1",
    "hyperliquidChain": "Mainnet",
    "destination": "0xf2743533df9c376a09da0b9810de8c457e28aadc",
    "sourceDex": "",
    "destinationDex": "",
    "token": "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
    "amount": "4.912352",
    "fromSubAccount": "",
    "nonce": 1768146914372
  },
  "nonce": 1768146914372
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x154dfe3cc1ac2f1b16c704332644d30201a300225caf4dedb916a98f80a00905)

## Field Reference

### Action Fields

| Field            | Type    | Description                    |
| ---------------- | ------- | ------------------------------ |
| `type`           | string  | Always `"sendAsset"`           |
| `destination`    | string  | Recipient address              |
| `sourceDex`      | boolean | Source is DEX (vs bridge)      |
| `destinationDex` | boolean | Destination is DEX (vs bridge) |
| `token`          | string  | Token to transfer              |
| `amount`         | string  | Amount to transfer             |
| `fromSubAccount` | boolean | Transfer from sub-account      |

## Use Cases

### Cross-Account Transfers

Track asset movements:

```python
def process_sendAsset_action(action):
    destination = action.get('destination')
    token = action.get('token')
    amount = action.get('amount')
    print(f"Asset transfer: {amount} {token} to {destination[:10]}...")
```

## Related Action Payloads

- [spotSend](https://www.dwellir.com/docs/hyperliquid/spotSend) - Spot token transfers
- [usdSend](https://www.dwellir.com/docs/hyperliquid/usdSend) - USD transfers

---

## SetGlobalAction payload - Global Parameters

# SetGlobalAction payload - Global Parameters

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `SetGlobalAction` payload records updates to global system parameters such as oracle prices and market configuration.

## Sample Data

```json
{
  "signature": {
    "r": "0x92258565da730223bbd076688bcdabb5826de44527ee6c407688aa376e3ff8ef",
    "s": "0x7783859200389c21fe5600f6cdb1ed8477d5c6b5da3ebd818b7d1494a9579c9b",
    "v": 28
  },
  "action": {
    "type": "SetGlobalAction",
    "pxs": [
      ["90802", "90762"],
      ["3114.6", "3113.3"],
      ["2.5905", "2.5878"]
    ],
    "externalPerpPxs": [
      ["0G", "0.87235"],
      ["2Z", "0.11722"],
      ["AAVE", "166.5"]
    ],
    "usdtUsdcPx": "0.9989012086704624",
    "nativePx": "24.4025"
  },
  "nonce": 1768146734571
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x1aaf367e0079ae3e1c28043326350b0000ea4e639b7ccd10be77e1d0bf7d8828)

## Field Reference

### Action Fields

| Field  | Type   | Description                               |
| ------ | ------ | ----------------------------------------- |
| `type` | string | Always `"SetGlobalAction"`                |
| `pxs`  | array  | Price updates \[bid, ask] for each market |

## Use Cases

### Oracle Price Monitoring

Track oracle price updates:

```python
def process_SetGlobalAction(action):
    prices = action.get('pxs', [])
    print(f"Oracle update: {len(prices)} markets")
```

## Related Action Payloads

- [noop](https://www.dwellir.com/docs/hyperliquid/noop) - Nonce invalidation
- [perpDeploy](https://www.dwellir.com/docs/hyperliquid/perpDeploy) - Market deployment

---

## setReferrer payload - Referral Codes

# setReferrer payload - Referral Codes

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `setReferrer` payload records assignment of a referral code to a Hyperliquid account.

## Sample Data

```json
{
  "signature": {
    "r": "0xf1d1526d59598ab867931fa78f9eedf4a76bada17a90cb2a8b804222774019cb",
    "s": "0x1eafd4a61d38331a80841682309b981f49e777094c2affe123f5cfd59293d047",
    "v": 28
  },
  "action": {
    "type": "setReferrer",
    "code": "PLACEHOLDER"
  },
  "nonce": 1768146913883
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xd6f62a16e52adfa7d86f04332644cd02033900fc802dfe797abed569a42eb992)

## Field Reference

### Action Fields

| Field  | Type   | Description                                 |
| ------ | ------ | ------------------------------------------- |
| `type` | string | Always `"setReferrer"`                      |
| `code` | string | Referral code to associate with the account |

## Referral Program

Hyperliquid's referral system allows:

- Referrers to earn a percentage of referred users' trading fees
- New users to potentially receive fee discounts
- Both parties to benefit from the relationship

## Use Cases

### Referral Analytics

Track referral code adoption and distribution:

```python
referral_counts = {}

def process_setReferrer_action(action):
    code = action.get('code')
    referral_counts[code] = referral_counts.get(code, 0) + 1
    print(f"Referral code used: {code} (total: {referral_counts[code]})")
```

### Influencer Tracking

Monitor which referral codes are most popular to identify influential promoters.

### Onboarding Analysis

Track referral usage patterns to understand user acquisition channels.

## Related Action Payloads

- [registerReferrer](https://www.dwellir.com/docs/hyperliquid/registerReferrer) - Referrer registration
- [claimRewards](https://www.dwellir.com/docs/hyperliquid/claimRewards) - Referral reward claims

---

## spotClearinghouseState - HyperCore Info Endpoint

# spotClearinghouseState - HyperCore Info Endpoint

Get spot trading account state and token balances for a user on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `spotClearinghouseState` endpoint is essential for spot traders, portfolio managers, and trading platforms who need to:

- **Track Token Balances** — Monitor available and held balances across all tokens
- **Portfolio Management** — Calculate total portfolio value across spot holdings
- **Trading Validation** — Verify sufficient balance before placing spot orders
- **Liquidity Management** — Track which funds are locked in open orders

## Request Parameters

- `type` (`string, required`): parameter: Must be `"spotClearinghouseState"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "spotClearinghouseState",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `balances` (`array, required`): Array of token balance objects

## Successful Response

```json
{
  "balances": [
    {
      "coin": "USDC",
      "token": 0,
      "total": "0.01261784",
      "hold": "0.0",
      "entryNtl": "0.0"
    },
    {
      "coin": "HYPE",
      "token": 150,
      "total": "0.00674734",
      "hold": "0.0",
      "entryNtl": "0.24186439"
    }
  ]
}
```

## Common Use Cases

### 1. Check Available Balance

Calculate available balance for a specific token:

```javascript
async function getAvailableBalance(userAddress, token) {
  const state = await getSpotClearinghouseState(userAddress);
  const balance = state.balances.find(b => b.coin === token);

  if (!balance) {
    return {
      token: token,
      available: 0,
      total: 0,
      hold: 0,
      exists: false
    };
  }

  const total = parseFloat(balance.total);
  const hold = parseFloat(balance.hold);
  const available = total - hold;

  return {
    token: token,
    available: available,
    total: total,
    hold: hold,
    exists: true
  };
}

// Usage
const usdcBalance = await getAvailableBalance(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  'USDC'
);

if (usdcBalance.available < 1000) {
  console.log('Insufficient USDC balance for trade');
}
```

### 2. Portfolio Value Calculator

Calculate total portfolio value in USD:

```javascript
async function calculatePortfolioValue(userAddress, prices) {
  const state = await getSpotClearinghouseState(userAddress);

  let totalValue = 0;
  const holdings = [];

  state.balances.forEach(balance => {
    const total = parseFloat(balance.total);
    if (total === 0) return;

    const price = prices[balance.coin] || 0;
    const value = total * price;
    totalValue += value;

    holdings.push({
      token: balance.coin,
      amount: total,
      price: price,
      value: value,
      percentage: 0 // Will calculate after
    });
  });

  // Calculate percentages
  holdings.forEach(h => {
    h.percentage = (h.value / totalValue) * 100;
  });

  // Sort by value
  holdings.sort((a, b) => b.value - a.value);

  return {
    totalValue: totalValue,
    holdings: holdings,
    tokenCount: holdings.length
  };
}

// Usage with example prices
const prices = { USDC: 1, ETH: 2500, BTC: 45000 };
const portfolio = await calculatePortfolioValue(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  prices
);

console.log(`Total Portfolio Value: $${portfolio.totalValue.toFixed(2)}`);
portfolio.holdings.forEach(h => {
  console.log(`${h.token}: $${h.value.toFixed(2)} (${h.percentage.toFixed(1)}%)`);
});
```

### 3. Validate Trade Feasibility

Check if user has sufficient balance for a trade:

```javascript
async function canExecuteTrade(userAddress, token, requiredAmount) {
  const balance = await getAvailableBalance(userAddress, token);

  if (!balance.exists) {
    return {
      canTrade: false,
      reason: `No ${token} balance found`,
      available: 0,
      required: requiredAmount
    };
  }

  if (balance.available < requiredAmount) {
    return {
      canTrade: false,
      reason: 'Insufficient balance',
      available: balance.available,
      required: requiredAmount,
      shortfall: requiredAmount - balance.available
    };
  }

  return {
    canTrade: true,
    available: balance.available,
    required: requiredAmount,
    remaining: balance.available - requiredAmount
  };
}

// Usage
const tradeCheck = await canExecuteTrade(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  'USDC',
  1000
);

if (!tradeCheck.canTrade) {
  console.error(`Cannot trade: ${tradeCheck.reason}`);
  console.error(`Required: ${tradeCheck.required}, Available: ${tradeCheck.available}`);
}
```

### 4. Monitor Locked Balances

Track which tokens have funds locked in orders:

```javascript
async function getLockedBalances(userAddress) {
  const state = await getSpotClearinghouseState(userAddress);

  const lockedBalances = state.balances
    .filter(b => parseFloat(b.hold) > 0)
    .map(b => ({
      token: b.coin,
      total: parseFloat(b.total),
      hold: parseFloat(b.hold),
      available: parseFloat(b.total) - parseFloat(b.hold),
      percentLocked: (parseFloat(b.hold) / parseFloat(b.total)) * 100
    }));

  return lockedBalances;
}

// Usage
const locked = await getLockedBalances('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`${locked.length} tokens with locked funds:\n`);

locked.forEach(l => {
  console.log(`${l.token}:`);
  console.log(`  Locked: ${l.hold} (${l.percentLocked.toFixed(1)}%)`);
  console.log(`  Available: ${l.available}`);
});
```

### 5. Balance Summary Report

Generate a comprehensive balance report:

```javascript
async function getBalanceSummary(userAddress) {
  const state = await getSpotClearinghouseState(userAddress);

  console.log('\n=== Spot Balance Summary ===\n');

  const nonZeroBalances = state.balances.filter(b => parseFloat(b.total) > 0);
  const lockedBalances = state.balances.filter(b => parseFloat(b.hold) > 0);

  console.log(`Total Tokens: ${nonZeroBalances.length}`);
  console.log(`Tokens with Orders: ${lockedBalances.length}\n`);

  console.log('Balances:');
  nonZeroBalances.forEach(balance => {
    const total = parseFloat(balance.total);
    const hold = parseFloat(balance.hold);
    const available = total - hold;

    console.log(`\n${balance.coin}:`);
    console.log(`  Total: ${balance.total}`);
    console.log(`  Available: ${available.toFixed(8)}`);
    if (hold > 0) {
      console.log(`  On Hold: ${balance.hold} ⚠️`);
    }
  });
}
```

## Best Practices

1. **Poll responsibly** — Don't poll more frequently than needed (every 5-10 seconds for active trading)
2. **Handle zero balances** — Token may exist with zero balance
3. **Check available balance** — Always calculate `total - hold` before placing orders
4. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
5. **Cache when appropriate** — Cache balance data briefly to reduce API calls

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get perpetual account state
- [**batchSpotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/batch-spot-clearinghouse-state): Batch query spot balances for multiple users
- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state) — Combine perp state, spot balances, and user abstraction in one request
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — See which orders are holding funds
- [**spotMeta**](https://www.dwellir.com/docs/hyperliquid/spot-meta) — Get spot trading asset metadata
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user fee rates for trading

***

*Access real-time Hyperliquid spot balances with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## spotMeta - HyperCore Info Endpoint

# spotMeta - HyperCore Info Endpoint

Get metadata for all available spot trading assets on Hyperliquid, including token details, decimal precision, and trading pair information.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `spotMeta` endpoint is essential for:

- **Spot Trading Interfaces** — Display available spot markets with correct token information
- **Token Discovery** — List all tradeable spot assets
- **Decimal Handling** — Format token amounts with correct precision
- **Token Validation** — Verify token addresses and canonical status

## Request Parameters

- `type` (`string, required`): parameter: Must be `"spotMeta"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "spotMeta"
}'
```

## Response Fields

- `universe` (`array, required`): Array of spot trading pair objects
- `tokens` (`array, required`): Array of token metadata objects

## Successful Response

```json
{
  "universe": [
    {
      "tokens": [0, 1],
      "name": "USDC/USDT"
    }
  ],
  "tokens": [
    {
      "name": "USDC",
      "szDecimals": 8,
      "weiDecimals": 8,
      "index": 0,
      "tokenId": "0x6d1e7cde53ba9467b783cb7c530ce054",
      "isCanonical": true,
      "fullName": "USD Coin"
    },
    {
      "name": "USDT",
      "szDecimals": 8,
      "weiDecimals": 8,
      "index": 1,
      "tokenId": "0x4ed5f9b9547c4fbb52be8b24fcb5e8ba",
      "isCanonical": true,
      "fullName": "Tether USD"
    }
  ]
}
```

## Common Use Cases

### 1. Format Token Amounts

```javascript
function formatTokenAmount(tokenName, amount, spotMeta) {
  const token = spotMeta.tokens.find(t => t.name === tokenName);
  if (!token) return amount.toString();

  return amount.toFixed(token.szDecimals);
}

// Usage
const spotMeta = await getSpotMeta();
console.log(formatTokenAmount('USDC', 1000.123456, spotMeta)); // "1000.12345600"
```

### 2. Build Token Selector

```javascript
async function getTokenList() {
  const spotMeta = await getSpotMeta();

  return spotMeta.tokens
    .filter(t => t.isCanonical)
    .map(token => ({
      symbol: token.name,
      fullName: token.fullName,
      tokenId: token.tokenId,
      decimals: token.szDecimals
    }));
}
```

### 3. Validate Token

```javascript
function isValidToken(tokenName, spotMeta) {
  return spotMeta.tokens.some(t => t.name === tokenName);
}
```

## Best Practices

1. **Cache spot metadata** for extended periods as it changes infrequently
2. **Use correct decimals** when formatting token amounts
3. **Filter canonical tokens** when presenting token lists to users
4. **Validate tokens** before attempting trades

## Related Endpoints

- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get perpetual trading pair metadata
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot account balances
- [**candles**](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles#discovering-markets) — Use spot `@INDEX` symbols as the `market` parameter for candle queries

***

*Access Hyperliquid spot market metadata with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## spotSend payload - Spot Asset Transfers

# spotSend payload - Spot Asset Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `spotSend` payload records a spot-token transfer between Hyperliquid addresses.

## Sample Data

```json
{
  "signature": {
    "r": "0x3054da3f8b58c8eb22dbb4da6c010bd6eeda1681122fca4230e8853ea0836119",
    "s": "0x638265740adb334844d7825bb267a1fec5d0e45ba27ae73b09197b5f49b5148",
    "v": 27
  },
  "action": {
    "type": "spotSend",
    "signatureChainId": "0x66eee",
    "hyperliquidChain": "Mainnet",
    "destination": "0xE2a0cC663aCFE5D7A9Cb82A743383297597A8fF3",
    "token": "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
    "amount": "98.43",
    "time": 1768146929220
  },
  "nonce": 1768146929220
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x2a4dd5ab257f1c0b2bc7043326459f01ec00ed90c0723addce1680fde472f5f5)

## Field Reference

### Action Fields

| Field              | Type   | Description                                  |
| ------------------ | ------ | -------------------------------------------- |
| `type`             | string | Always `"spotSend"`                          |
| `signatureChainId` | string | Chain ID for EIP-712 signing                 |
| `hyperliquidChain` | string | Target chain: `"Mainnet"` or `"Testnet"`     |
| `destination`      | string | Recipient's Ethereum address                 |
| `token`            | string | Token identifier (symbol:contract format)    |
| `amount`           | string | Amount to transfer (human-readable decimals) |
| `time`             | number | Transaction timestamp                        |

## Token Identifier Format

Tokens are identified using the format `SYMBOL:CONTRACT_HASH`:

- `HYPE:0x0d01dc56dcaaca66ad901c959b4011ec` - HYPE token
- Other spot tokens follow the same pattern

## Use Cases

### Token Flow Analysis

Track spot token movements across the network:

```python
def process_spotSend_action(action):
    destination = action.get('destination')
    token = action.get('token')
    amount = action.get('amount')

    token_symbol = token.split(':')[0]
    print(f"Spot transfer: {amount} {token_symbol} to {destination[:10]}...")
```

### Whale Tracking

Monitor large token transfers to identify significant market participants.

### Exchange Flow Monitoring

Track token deposits and withdrawals from exchange-related addresses.

## Related Action Payloads

- [usdSend](https://www.dwellir.com/docs/hyperliquid/usdSend) - USD transfers between accounts
- [sendAsset](https://www.dwellir.com/docs/hyperliquid/sendAsset) - Generic asset transfer
- [subAccountSpotTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountSpotTransfer) - Sub-account spot transfers

---

## spotUser payload - Spot User Configuration

# spotUser payload - Spot User Configuration

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `spotUser` payload records a signed update to a user's spot-account preferences.

## How to Read It

The sample payload shows the `toggleSpotDusting` configuration, which changes account-level behavior for spot dusting. This action is a stateful preference update. Signature, nonce, and final execution result come from the surrounding signed-action envelope and the paired response in [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks).

## Sample Data

```json
{
  "signature": {
    "r": "0xfb9cd389323a6b281ee513f1b1ddd0fffc21caf970e4d621da117af34c8ae800",
    "s": "0x7c5d80c2e1a15f46eed277e953453e87c1f65e7ba74b621a520d779ee6766e2b",
    "v": 28
  },
  "action": {
    "type": "spotUser",
    "toggleSpotDusting": {
      "optOut": true
    }
  },
  "nonce": 1768151177912,
  "expiresAfter": 1768151192082
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xa0c634450ebcfd6ca23f0433271125020482002aa9b01c3e448edf97cdb0d757)

## Field Reference

### Envelope Fields

| Field          | Type   | Description                                              |
| -------------- | ------ | -------------------------------------------------------- |
| `signature`    | object | ECDSA signature for the signed action                    |
| `nonce`        | number | Replay-protection nonce used for ordering and uniqueness |
| `expiresAfter` | number | Optional expiry timestamp for time-bounded execution     |

### Action Fields

| Field               | Type   | Description                     |
| ------------------- | ------ | ------------------------------- |
| `type`              | string | Always `"spotUser"`             |
| `toggleSpotDusting` | object | Spot dusting preference payload |

### `toggleSpotDusting` Fields

| Field    | Type    | Description                                                                   |
| -------- | ------- | ----------------------------------------------------------------------------- |
| `optOut` | boolean | Whether the user opts out of the dusting behavior shown in the sample payload |

## Processing Guidance

- Treat `spotUser` as an account settings update, not an economic transfer.
- Preserve unknown nested fields if the protocol adds more spot-user preferences later. Dispatch first on `action.type`, then parse the nested settings defensively.
- Use the paired response from the same block bundle to determine whether the preference change actually took effect.
- If your product surfaces account settings history, store the transaction hash and nonce alongside the parsed preference payload.

## Common Use Cases

### Settings History

Record when users changed spot-account behavior and tie the change back to the exact signed action that produced it.

### Account State Reconstruction

Replay `spotUser` actions in block order to rebuild a user's spot-account preferences over time.

## Related Action Payloads

- [spotSend](https://www.dwellir.com/docs/hyperliquid/spotSend) for spot-asset transfers
- [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) for block and response pairing

---

## StreamActiveAssetCtx - Stream Perp Market Context

# StreamActiveAssetCtx - Stream Perp Market Context

`StreamActiveAssetCtx` sends the current market context for one default-DEX perp as a live Info-derived view rather than a block-cadence stream.

## Request and opening behavior

`coin` is required and must identify a perp on the default DEX. Spot and outcome identifiers return `INVALID_ARGUMENT`. A ready subscription immediately receives the current context, then a complete replacement whenever that coin's values change.

`time` identifies when the endpoint made the update available, not a block or upstream timestamp. `premium` and `mid_px` are unset, and `impact_pxs` is empty, when a market has no book.

## Request Parameters

- `coin` (`string, required`): One case-sensitive perp coin on the default DEX; spot and outcome identifiers are invalid.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamActiveAssetCtx(ctx, &pb.ActiveAssetCtxRequest{Coin: "BTC"})
    if err != nil {
        log.Fatal(err)
    }
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("coin=%s update_time=%d funding=%s open_interest=%s mark=%s", update.GetCoin(), update.GetTime(), update.GetFunding(), update.GetOpenInterest(), update.GetMarkPx())
    }
}
```

## Response Fields

- `coin` (`string, required`): Default-DEX perp coin identifier.
- `time` (`int64, required`): Endpoint update time in Unix milliseconds, not block or upstream time.
- `funding` (`string, required`): Hourly funding rate as a decimal string.
- `open_interest` (`string, required`): Open interest as a decimal string.
- `prev_day_px` (`string, required`): Price 24 hours before the upstream context snapshot.
- `day_ntl_vlm` (`string, required`): Rolling 24-hour notional volume.
- `premium` (`optional string, optional`): Mark-oracle premium, unset when the market has no book.
- `oracle_px` (`string, required`): Oracle price as a decimal string.
- `mark_px` (`string, required`): Mark price as a decimal string.
- `mid_px` (`optional string, optional`): Book midpoint, unset when the market has no book.
- `impact_pxs` (`repeated string, required`): Bid and ask impact prices; empty when the market has no book.
- `day_base_vlm` (`string, required`): Rolling 24-hour base-unit volume.

## Successful Response

```protobuf
coin: "BTC"
time: 1785736814057
funding: "0.0000125"
open_interest: "19234.55"
prev_day_px: "112500.0"
day_ntl_vlm: "985000000.25"
premium: "0.00018"
oracle_px: "114230.0"
mark_px: "114250.0"
mid_px: "114250.5"
impact_pxs: "114249.0"
impact_pxs: "114252.0"
day_base_vlm: "8650.75"
```

## Error Responses

### Invalid coin

- Code: `INVALID_ARGUMENT`
- Description: coin is empty, unknown, not a perp, or not on the default DEX.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### Current data unavailable

- Code: `UNAVAILABLE`
- Description: No current context is available, or the latest data is stale.

### Context removed or stream state reset

- Code: `ABORTED`
- Description: The coin is no longer tracked or the stream state reset.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

Subscriber lag drops obsolete snapshots in-band. An upstream outage produces silence. `UNAVAILABLE` means no fresh data is available, `FAILED_PRECONDITION` means the stream is unavailable on this endpoint, and `ABORTED` means its state reset or the coin is no longer tracked. See the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for shared errors.

Related reference: [StreamAllMids](https://www.dwellir.com/docs/hyperliquid/stream_all_mids).

---

## StreamAllFills - Stream All Fills

# StreamAllFills - Stream All Fills

`StreamAllFills` sends every live fill in scope. Each `Fill` is one account's execution with position context. Within one block, fills from one match share `(coin, tid)`.

Across blocks, include the frame's `block_number` in the match key. Retain account and order identity when deduplicating individual fills.

## Request and live-only behavior

Empty `coins` and `users` lists select all fills. Coin names match exactly and are not validated against the current universe; unknown names simply never match. User addresses match the fill's own `user` field case-insensitively. Non-empty coin and user filters combine using AND semantics.

The stream has no opening snapshot or historical backfill. Every source block containing fills advances `sequence`. If filtering removes every fill, the frame remains present with an empty `fills` list.

## Request Parameters

- `coins` (`repeated string, optional`): Optional exact coin scope; empty means all coins, and unknown coins simply never match.
- `users` (`repeated string, optional`): Optional fill-owner addresses matched case-insensitively; combines with coins using AND semantics.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamAllFills(ctx, &pb.AllFillsRequest{
        Coins: []string{"BTC", "ETH"},
        Users: []string{"0x1111111111111111111111111111111111111111"},
    })
    if err != nil {
        log.Fatal(err)
    }
    var last uint64
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d sequence=%d fills=%d", update.GetBlockNumber(), update.GetSequence(), len(update.GetFills()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Source block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the first live frame.
- `fills` (`repeated Fill, required`): Matching per-account executions; may be empty after filtering.
- `fills.user` (`string, required`): Account this fill belongs to.
- `fills.coin` (`string, required`): Native coin identifier.
- `fills.px` (`string, required`): Execution price as a decimal string.
- `fills.sz` (`string, required`): Executed size as a decimal string.
- `fills.side` (`string, required`): Native side B or A.
- `fills.time` (`int64, required`): Execution time in Unix milliseconds.
- `fills.hash` (`string, required`): Transaction hash.
- `fills.tid` (`uint64, required`): Within one block, use (coin, tid). Across blocks, include the frame's block_number. Retain account and order identity for individual fills.
- `fills.crossed` (`bool, required`): True when this account was the taker.
- `fills.dir` (`string, required`): Human-readable position direction.
- `fills.start_position` (`string, required`): Signed position immediately before this fill.
- `fills.oid` (`uint64, required`): Filled order identifier.
- `fills.closed_pnl` (`string, required`): Closed profit and loss as a decimal string.
- `fills.fee` (`string, required`): Trading fee as a decimal string.
- `fills.fee_token` (`string, required`): Fee denomination.
- `fills.builder` (`FillBuilder, optional`): Builder attribution, unset for fills without a builder.
- `fills.builder.address` (`string, required`): Builder address.
- `fills.builder.fee` (`string, required`): Builder fee charged on this fill.
- `fills.cloid` (`optional string, optional`): Client order identifier when present.
- `fills.twap_id` (`optional uint64, optional`): TWAP identifier when the fill came from a TWAP order.
- `fills.liquidation` (`FillLiquidation, optional`): Liquidation metadata, unset for non-liquidation fills.
- `fills.liquidation.liquidated_user` (`string, required`): Liquidated account address.
- `fills.liquidation.mark_px` (`string, required`): Liquidation mark price.
- `fills.liquidation.method` (`string, required`): Native liquidation method.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
sequence: 1
fills: {
  user: "0x1111111111111111111111111111111111111111"
  coin: "BTC"
  px: "114250.0"
  sz: "0.25"
  side: "B"
  time: 1785736814057
  hash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  tid: 99887766
  crossed: true
  dir: "Open Long"
  start_position: "0.0"
  oid: 123456789
  closed_pnl: "0.0"
  fee: "0.285625"
  fee_token: "USDC"
  builder: { address: "0x2222222222222222222222222222222222222222" fee: "0.01" }
  cloid: "0x00112233445566778899aabbccddeeff"
  twap_id: 778899
  liquidation: { liquidated_user: "0x3333333333333333333333333333333333333333" mark_px: "114200.0" method: "market" }
}
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: A coin entry or user address is malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: Live fills are not currently available.

### Lost live fills

- Code: `ABORTED`
- Description: Frame loss or a stream state reset ended this live-only stream.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require contiguous `sequence` values. A gap or `ABORTED` indicates loss; reconnect for new live fills, then use [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) or [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data) to recover the missing interval. See the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for common errors.

Related references: [StreamUserFills](https://www.dwellir.com/docs/hyperliquid/stream_user_fills), [StreamBuilderFills](https://www.dwellir.com/docs/hyperliquid/stream_builder_fills), and [StreamLiquidationFills](https://www.dwellir.com/docs/hyperliquid/stream_liquidation_fills).

---

## StreamAllMids - Stream All Perp Mid Prices

# StreamAllMids - Stream All Perp Mid Prices

`StreamAllMids` sends the complete default-DEX perp mid-price map as a live Info-derived view rather than a block-cadence stream.

## Request and opening behavior

The request has no fields. A warm subscription immediately receives the current map, then receives a complete replacement when its values change. `time` identifies when the endpoint made the update available, not a block or upstream timestamp.

For a bookless market, the map uses the last-trade fallback. Every frame supersedes the previous map.

## Request Parameters

This method accepts no parameters.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamAllMids(ctx, &pb.AllMidsRequest{})
    if err != nil {
        log.Fatal(err)
    }
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("update_time=%d mids=%v", update.GetTime(), update.GetMids())
    }
}
```

## Response Fields

- `time` (`int64, required`): Endpoint update time in Unix milliseconds, not block or upstream time.
- `mids` (`map<string, string>, required`): Complete default-DEX perp map from coin to decimal mid price or last-trade fallback.

## Successful Response

```protobuf
time: 1785736814057
mids: { key: "BTC" value: "114250.5" }
mids: { key: "ETH" value: "3650.25" }
```

## Error Responses

### Invalid request

- Code: `INVALID_ARGUMENT`
- Description: The request is malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### Current data unavailable

- Code: `UNAVAILABLE`
- Description: No current map is available, or the latest data is stale.

### Stream state reset

- Code: `ABORTED`
- Description: The stream state reset; reconnect after it recovers.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

Subscriber lag drops obsolete maps in-band. An upstream outage produces silence rather than closing an established stream. `UNAVAILABLE` means a new subscription has no fresh data, `FAILED_PRECONDITION` means the stream is unavailable on this endpoint, and `ABORTED` means its state reset. See the [shared market-stream contract](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for common errors.

Related reference: [StreamActiveAssetCtx](https://www.dwellir.com/docs/hyperliquid/stream_active_asset_ctx).

---

## StreamBbo - Stream Best Bid and Offer

# StreamBbo - Stream Best Bid and Offer

`StreamBbo` sends the best bid and ask for each requested coin. It opens with the current top of book for every coin, then emits only when that coin's top changes.

## Request and opening behavior

`coins` is required and accepts `1` through `20` distinct, case-sensitive native coin identifiers. Duplicates are removed before enforcing the cap. Empty lists, blank entries, wildcard entries, and unknown or disabled coins return `INVALID_ARGUMENT`.

Each coin has an independent stream order. Cross-coin ordering is unspecified. `bid` or `ask` is unset when that side of the book is empty.

## Request Parameters

- `coins` (`repeated string, required`): One to 20 distinct, case-sensitive native coin identifiers; duplicates are ignored before applying the cap.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "errors"
    "io"
    "log"
    "os"
    "os/signal"
    "syscall"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT")
    apiKey := os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
    ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamBbo(ctx, &pb.BboRequest{Coins: []string{"BTC", "ETH"}})
    if err != nil {
        log.Fatal(err)
    }
    for {
        update, err := stream.Recv()
        if errors.Is(err, io.EOF) {
            return
        }
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("coin=%s block=%d bid=%v ask=%v", update.GetCoin(), update.GetBlockNumber(), update.GetBid(), update.GetAsk())
    }
}
```

## Response Fields

- `coin` (`string, required`): Coin whose top of book changed or whose opening value is being sent.
- `time` (`int64, required`): Frame block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `bid` (`L2Level, optional`): Best bid; unset when the bid side is empty.
- `bid.px` (`string, required`): Best-bid price as a decimal string.
- `bid.sz` (`string, required`): Aggregated size at the best bid.
- `bid.n` (`uint32, required`): Number of resting orders at the best bid.
- `ask` (`L2Level, optional`): Best ask; unset when the ask side is empty.
- `ask.px` (`string, required`): Best-ask price as a decimal string.
- `ask.sz` (`string, required`): Aggregated size at the best ask.
- `ask.n` (`uint32, required`): Number of resting orders at the best ask.

## Successful Response

```protobuf
coin: "BTC"
time: 1785736814057
block_number: 1058646974
bid: { px: "114250.0" sz: "1.35" n: 4 }
ask: { px: "114251.0" sz: "0.82" n: 3 }
```

## Error Responses

### Invalid coin list

- Code: `INVALID_ARGUMENT`
- Description: The list is empty, exceeds 20 distinct coins, contains a blank or wildcard, or names an unavailable coin.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested BBO view is not ready.

### Stream state reset

- Code: `ABORTED`
- Description: The requested view or stream state reset; reconnect for fresh opening values.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

The stream recovers from subscriber lag by invalidating its dedup state and re-sending the current top of book on a later window. That recovery frame may repeat a value already observed. `ABORTED` means the stream state reset; reconnect to receive fresh opening values. See the [shared market-stream contract](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for common errors and delivery rules.

Related references: [StreamL2Book](https://www.dwellir.com/docs/hyperliquid/stream_l2_book) and the [Order Book WebSocket BBO channel](https://www.dwellir.com/docs/hyperliquid/bbo).

---

## StreamBlocks - Real-time Block Streaming

# StreamBlocks - Real-time Block Streaming

Stream continuous block data starting from a position, providing real-time access to Hyperliquid blockchain state changes.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`StreamBlocks` is essential for:

- **Blockchain Monitoring** - Track all network activity and state changes
- **Block Explorers** - Build real-time blockchain data applications
- **Analytics Systems** - Collect comprehensive blockchain metrics
- **Compliance & Auditing** - Monitor all network transactions and events

Method signature

```protobuf
rpc StreamBlocks(StreamRequest) returns (stream Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`. Explicit zero is invalid. A positioned call replays from the selected record and then tails live; an empty request tails newly written blocks. Blocks do not accept filters. Set `progress` to opt in to [progress frames](#progress-frames).

```protobuf
position: {
  block_number: 1058646974
}
```

Each `Record` returns optional sequential `block_number` and Unix-millisecond `timestamp` cursors plus the raw `replica_cmds` bytes in `data`. `block_number` is distinct from the potentially skipping consensus `abci_block.round`. A pruned position returns `NOT_FOUND`; malformed cursors and filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to tail newly written records.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `progress.interval_ms` (`uint32, optional`): Set progress to opt in to progress frames; leave it unset for none. Longest silence in milliseconds before a progress frame. 0 selects the feed default, currently 20000 within bounds of 10000 to 60000; ListFeeds reports the bounds in FeedInfo.progress.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamBlocks
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the replica_cmds.
- `progress` (`StreamProgress, optional`): Set only on progress frames, which leave data, block_number, and timestamp unset. Check it before decoding data.
- `progress.scanned_through.block_number` (`int64, optional`): Inclusive cursor of the newest block the stream examined, sent or removed by the filter. A valid resume position; unset until the stream has examined a record.
- `progress.timestamp` (`optional int64, optional`): Source time at scanned_through in Unix milliseconds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"abci_block\":{\"round\":1058646981,\"signed_action_bundles\":[]},\"resps\":{\"Full\":[]}}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter was supplied to a feed that does not support filtering.

#### Invalid progress request

- Code: `INVALID_ARGUMENT`
- Description: A nonzero progress.interval_ms is outside the bounds advertised in FeedInfo.progress.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Replay capacity is temporarily unavailable; retry with backoff.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Progress frames do not reset the timeout. Reconnect from the last cursor received.

#### Records lost

- Code: `DATA_LOSS`
- Description: The stream lost records, for example because it fell behind the live feed. It ends before sending any cursor past them; reconnect from the last cursor received to re-read the gap.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamBlocks
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 Block wrapper.

### Successful Response

```protobuf
message Block {
  bytes data = 1;
}
```

```protobuf
rpc StreamBlocks(Position) returns (stream Block) {}
```

V2 accepts the inclusive cursor fields `block_height` and `timestamp_ms`; an empty `Position` tails new blocks. It returns the source JSON in `Block.data`.

## Response Stream

V3 carries the JSON-encoded `replica_cmds` block in `Record.data`.

V2 carries the JSON-encoded `replica_cmds` block in `Block.data`.

Decode the `data` field to access:

- Block header information (consensus `round`, timestamp `time`)
- Transaction data and execution results
- State changes and events
- Validator signatures and consensus data
  - Note: The sample format does not include a top-level block hash; bundle hashes are present per `signed_action_bundles`.

## Full Block Spec

`StreamBlocks` emits a JSON payload matching Hyperliquid's `replica_cmds` BlockData. Below is the exact structure.

Top-level keys (always present):

```json
{
  "abci_block": {
    "time": "2025-09-08T06:41:57.997372546",  // ISO-8601 with nanosecond precision
    "round": 992814678,                        // HyperBFT consensus round; it can skip
    "parent_round": 992814677,                 // Parent consensus round; do not assume round - 1
    "proposer": "0x5ac99df645f3414876c816caa18b2d234024b487", // 40 hex chars, lowercase
    "hardfork": {
      "version": 57,                           // Protocol version number
      "round": 990500929                       // Block when this version activated
    },
    "signed_action_bundles": [                 // Array of [hash, bundle_data] pairs
      [
        "0xb4b1f5a9c233f9d90fd24b9961fd12708b36cc3d56f8fda47f32b667ee8d1227", // Bundle hash (64 hex)
        {
          "signed_actions": [                  // Array of transactions in this bundle
            {
              "signature": {
                "r": "0xd931f13565ae66c3bc41a05da4180bb795dbd9ed2d365efaf639fd23b3774ac6",
                "s": "0x4a7a0534bf0a4238dfe404a88d335ab4c9b8222909100d773635e328d2ab864c",
                "v": 27                        // Recovery ID: always 27 or 28
              },
              "action": {
                "type": "order",               // Action type identifier
                "orders": [{                   // Type-specific payload
                  "a": 170,                    // Asset ID
                  "b": true,                   // Buy=true, Sell=false
                  "p": "0.038385",             // Price as string
                  "s": "1514",                 // Size as string
                  "r": false,                  // Reduce-only flag
                  "t": {
                    "limit": {
                      "tif": "Ioc"             // Time-in-force: Ioc/Alo/Gtc
                    }
                  },
                  "c": "0x7192c49bcadb32d394e38617ea99cc09" // Client order ID
                }]
              },
              "nonce": 1757313597362           // Unique transaction nonce
            }
            // ... more signed_actions
          ],
          "broadcaster": "0x67e451964e0421f6e7d07be784f35c530667c2b3", // Who sent bundle
          "broadcaster_nonce": 1757313597367  // Bundle-level nonce
        }
      ]
      // ... more bundles (typically 1-6 total)
    ]
  },
  "resps": {
    "Full": [                                  // Matches signed_action_bundles structure
      [
        "0xb4b1f5a9c233f9d90fd24b9961fd12708b36cc3d56f8fda47f32b667ee8d1227", // Same bundle hash
        [                                      // One response per signed_action
          {
            "user": "0xecb63caa47c7c4e77f60f1ce858cf28dc2b82b00", // Address of action signer
            "res": {
              "status": "ok",                  // "ok" or "err"
              "response": {
                "type": "order",               // Response type
                "data": {
                  "statuses": [{
                    "filled": {                // Order state: filled/resting/error
                      "totalSz": "1514.0",     // Filled size
                      "avgPx": "0.038385",     // Average fill price
                      "oid": 156190414943,     // Order ID assigned
                      "cloid": "0x7192c49bcadb32d394e38617ea99cc09" // Client order ID
                    }
                  }]
                }
              }
            }
          }
          // ... more responses (one per action)
        ]
      ]
      // ... more response bundles (matches signed_action_bundles count)
    ]
  }
}
```

### Bundle Entry Structure

```jsonc
[
  "0x...", // bundle_hash
  {
    "signed_actions": [ /* SignedAction */ ],
    "broadcaster": "0x...",
    "broadcaster_nonce": 1757313597367
  }
]
```

### SignedAction Envelope

Common fields across all actions:

```jsonc
{
  "signature": { "r": "0x...", "s": "0x...", "v": 27 },
  "action": { "type": "order" },               // Action type identifier
  "nonce": 1757313597362,
  "vaultAddress": "0x...",                      // optional
  "expiresAfter": 1757313718705                 // optional
}
```

### Data Guarantees

- `abci_block` and `resps.Full` are always present.
- `resps.Full.length === abci_block.signed_action_bundles.length`.
- For each bundle, `responses.length === signed_actions.length`.
- `abci_block.round` and `abci_block.parent_round` are HyperBFT consensus rounds, not sequential block numbers; rounds can skip.
- The transport's block cursor uses the sequential block-number axis. Do not derive it from `abci_block.round`.
- Timestamp `abci_block.time` is ISO-8601 with nanosecond precision (treat as UTC if no suffix).

### Developer Tips

- Dispatch on `action.type` and handle new types defensively.
- Store `bundle_hash` as the stable join key between actions and responses.
- Normalize prices/sizes (strings) to numeric types as appropriate.

***

## Action Types Reference

The pages below document action payloads returned inside `StreamBlocks` and `GetBlock`
block data. They are not callable gRPC methods, and Dwellir's gRPC API does not submit
Hyperliquid write actions.

Each block contains signed action bundles where individual actions are categorized by type. Dispatch on `action.type` to process different categories.

### Trading Actions

Core order management and execution operations.

| Action Type                                                          | Description                                   |
| -------------------------------------------------------------------- | --------------------------------------------- |
| [order](https://www.dwellir.com/docs/hyperliquid/order)                   | Limit, market, and trigger order submissions  |
| [cancel](https://www.dwellir.com/docs/hyperliquid/cancel)                 | Order cancellations by order ID               |
| [cancelByCloid](https://www.dwellir.com/docs/hyperliquid/cancelByCloid)   | Order cancellations by client order ID        |
| [batchModify](https://www.dwellir.com/docs/hyperliquid/batchModify)       | Batched order modifications                   |
| [modify](https://www.dwellir.com/docs/hyperliquid/modify)                 | Single-order modifications                    |
| [scheduleCancel](https://www.dwellir.com/docs/hyperliquid/scheduleCancel) | Scheduled cancellation settings               |
| [twapOrder](https://www.dwellir.com/docs/hyperliquid/twapOrder)           | Time-weighted average price order submissions |
| [twapCancel](https://www.dwellir.com/docs/hyperliquid/twapCancel)         | TWAP order cancellations                      |

### Transfer Actions

Asset movement between accounts and withdrawals.

| Action Type                                                              | Description                                    |
| ------------------------------------------------------------------------ | ---------------------------------------------- |
| [spotSend](https://www.dwellir.com/docs/hyperliquid/spotSend)                 | Spot asset transfers to another address        |
| [sendAsset](https://www.dwellir.com/docs/hyperliquid/sendAsset)               | Generic asset transfer                         |
| [usdClassTransfer](https://www.dwellir.com/docs/hyperliquid/usdClassTransfer) | USD-class asset transfers between margin modes |
| [withdraw3](https://www.dwellir.com/docs/hyperliquid/withdraw3)               | External withdrawal requests                   |
| [usdSend](https://www.dwellir.com/docs/hyperliquid/usdSend)                   | USD transfers to another address               |

### Risk Management Actions

Leverage and margin configuration.

| Action Type                                                                      | Description                            |
| -------------------------------------------------------------------------------- | -------------------------------------- |
| [updateLeverage](https://www.dwellir.com/docs/hyperliquid/updateLeverage)             | Position leverage updates              |
| [updateIsolatedMargin](https://www.dwellir.com/docs/hyperliquid/updateIsolatedMargin) | Isolated-margin adjustments            |
| [userPortfolioMargin](https://www.dwellir.com/docs/hyperliquid/userPortfolioMargin)   | Portfolio-margin configuration changes |

### Permissions Actions

Agent authorization and trading permissions.

| Action Type                                                                                | Description                             |
| ------------------------------------------------------------------------------------------ | --------------------------------------- |
| [approveAgent](https://www.dwellir.com/docs/hyperliquid/approveAgent)                           | Agent trading authorizations            |
| [approveBuilderFee](https://www.dwellir.com/docs/hyperliquid/approveBuilderFee)                 | Builder-fee approvals for order routing |
| [userDexAbstraction](https://www.dwellir.com/docs/hyperliquid/userDexAbstraction)               | User DEX abstraction settings           |
| [agentEnableDexAbstraction](https://www.dwellir.com/docs/hyperliquid/agentEnableDexAbstraction) | Agent-managed DEX abstraction settings  |

### SubAccount Actions

Sub-account creation and management.

| Action Type                                                                          | Description                                  |
| ------------------------------------------------------------------------------------ | -------------------------------------------- |
| [subAccountTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountTransfer)         | Main-account and sub-account asset transfers |
| [createSubAccount](https://www.dwellir.com/docs/hyperliquid/createSubAccount)             | Sub-account creation requests                |
| [subAccountModify](https://www.dwellir.com/docs/hyperliquid/subAccountModify)             | Sub-account setting changes                  |
| [subAccountSpotTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountSpotTransfer) | Sub-account spot transfers                   |

### Vault Actions

Vault creation, deposits, and position management.

| Action Type                                                                                      | Description                     |
| ------------------------------------------------------------------------------------------------ | ------------------------------- |
| [createVault](https://www.dwellir.com/docs/hyperliquid/createVault)                                   | Trading-vault creation requests |
| [vaultTransfer](https://www.dwellir.com/docs/hyperliquid/vaultTransfer)                               | Vault deposits and withdrawals  |
| [NetChildVaultPositionsAction](https://www.dwellir.com/docs/hyperliquid/NetChildVaultPositionsAction) | Net child vault positions       |

### Validator Actions

Consensus and cross-chain bridge operations.

| Action Type                                                                                              | Description                                 |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| [VoteEthDepositAction](https://www.dwellir.com/docs/hyperliquid/VoteEthDepositAction)                         | Validator vote on ETH deposit               |
| [VoteEthFinalizedWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/VoteEthFinalizedWithdrawalAction) | Validator vote on finalized ETH withdrawal  |
| [ValidatorSignWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/ValidatorSignWithdrawalAction)       | Validator withdrawal signatures             |
| [voteAppHash](https://www.dwellir.com/docs/hyperliquid/voteAppHash)                                           | Validator votes on application state hashes |

### EVM Actions

HyperEVM transaction execution and configuration.

| Action Type                                                        | Description              |
| ------------------------------------------------------------------ | ------------------------ |
| [evmRawTx](https://www.dwellir.com/docs/hyperliquid/evmRawTx)           | Raw EVM transactions     |
| [evmUserModify](https://www.dwellir.com/docs/hyperliquid/evmUserModify) | EVM user setting changes |

### Security Actions

Multi-signature and account security.

| Action Type                                                                        | Description                                    |
| ---------------------------------------------------------------------------------- | ---------------------------------------------- |
| [multiSig](https://www.dwellir.com/docs/hyperliquid/multiSig)                           | Multi-signature operation                      |
| [convertToMultiSigUser](https://www.dwellir.com/docs/hyperliquid/convertToMultiSigUser) | Account conversions to multi-signature control |

### Referral Actions

Referral program management.

| Action Type                                                              | Description               |
| ------------------------------------------------------------------------ | ------------------------- |
| [setReferrer](https://www.dwellir.com/docs/hyperliquid/setReferrer)           | Account referrer settings |
| [registerReferrer](https://www.dwellir.com/docs/hyperliquid/registerReferrer) | Referrer registrations    |

### Market Actions

Perpetual market deployment.

| Action Type                                                  | Description                  |
| ------------------------------------------------------------ | ---------------------------- |
| [perpDeploy](https://www.dwellir.com/docs/hyperliquid/perpDeploy) | Perpetual-market deployments |

### Rewards Actions

Reward claiming operations.

| Action Type                                                      | Description               |
| ---------------------------------------------------------------- | ------------------------- |
| [claimRewards](https://www.dwellir.com/docs/hyperliquid/claimRewards) | Accumulated reward claims |

### Staking Actions

Token delegation and staking.

| Action Type                                                        | Description                                   |
| ------------------------------------------------------------------ | --------------------------------------------- |
| [cDeposit](https://www.dwellir.com/docs/hyperliquid/cDeposit)           | Native-token transfers from spot into staking |
| [cWithdraw](https://www.dwellir.com/docs/hyperliquid/cWithdraw)         | Native-token transfers from staking to spot   |
| [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) | Validator delegation changes                  |

### Lending Actions

Borrow and lending operations.

| Action Type                                                  | Description                                             |
| ------------------------------------------------------------ | ------------------------------------------------------- |
| [borrowLend](https://www.dwellir.com/docs/hyperliquid/borrowLend) | Borrowing, repayment, supply, and withdrawal operations |

### Spot Actions

Spot market configuration.

| Action Type                                              | Description             |
| -------------------------------------------------------- | ----------------------- |
| [spotUser](https://www.dwellir.com/docs/hyperliquid/spotUser) | Spot user configuration |

### Protocol and Control Actions

Protocol parameter, request-weight, and nonce-control payloads.

| Action Type                                                                      | Description                                           |
| -------------------------------------------------------------------------------- | ----------------------------------------------------- |
| [noop](https://www.dwellir.com/docs/hyperliquid/noop)                                 | Used-nonce markers for invalidating in-flight actions |
| [SetGlobalAction](https://www.dwellir.com/docs/hyperliquid/SetGlobalAction)           | Global system parameter changes                       |
| [reserveRequestWeight](https://www.dwellir.com/docs/hyperliquid/reserveRequestWeight) | Request-weight reservations                           |

***

## Progress Frames

Progress frames are an application-level heartbeat. Set `StreamRequest.progress` to receive one after each interval of silence. Blocks are not filterable, so a healthy stream is rarely silent for a full interval. Here the heartbeat mainly keeps the stream open through idle-limited proxies, which HTTP/2 keepalive pings do not, and exposes a stalled feed.

A progress frame sets `Record.progress.scanned_through.block_number` and leaves the data fields unset, so check `progress` before decoding `data`. Persist `scanned_through` as an inclusive resume cursor. See [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) for the full contract.

V2 streams do not send progress frames. Use the V3 method to opt in.

## Best Practices

1. **Connection Management**: Implement robust reconnection logic with exponential backoff
2. **Memory Management**: Use bounded collections for storing recent blocks to prevent memory leaks
3. **Performance**: Process blocks asynchronously to avoid blocking the stream
4. **Error Recovery**: Handle various error types (network, parsing, processing) gracefully
5. **Resource Cleanup**: Properly close streams and connections on shutdown

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint
- **Unavailable Cursors**: A cursor outside retained history returns `NOT_FOUND`
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working implementations in Go, Python, and Node.js
- **[Copy Trading Bot](https://github.com/dwellir-public/gRPC-code-examples/tree/main/copy-trading-bot)** - Production-ready trading bot example

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamBuilderFills - Stream Builder Fills

# StreamBuilderFills - Stream Builder Fills

`StreamBuilderFills` sends live fills whose nested `builder.address` equals the requested builder. Fills without builder attribution never match.

## Request and live-only behavior

`builder` is a required 0x-prefixed address and matches case-insensitively. The zero address has no special meaning. Empty `coins` selects every coin; supplied coin names match exactly and unknown names simply never match.

The stream has no opening snapshot or backfill. A source block can still emit an empty `fills` list after filtering so that `sequence` remains contiguous.

## Request Parameters

- `builder` (`string, required`): Required 0x-prefixed builder address matched against builder.address case-insensitively.
- `coins` (`repeated string, optional`): Optional exact coin scope; empty means all coins, and unknown coins simply never match.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamBuilderFills(ctx, &pb.BuilderFillsRequest{
        Builder: "0x2222222222222222222222222222222222222222",
        Coins: []string{"BTC", "ETH"},
    })
    if err != nil {
        log.Fatal(err)
    }
    var last uint64
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d sequence=%d fills=%d", update.GetBlockNumber(), update.GetSequence(), len(update.GetFills()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Source block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the first live frame.
- `fills` (`repeated Fill, required`): Fills carrying the requested builder attribution; may be empty after coin filtering.
- `fills.user` (`string, required`): Account this fill belongs to.
- `fills.coin` (`string, required`): Native coin identifier.
- `fills.px` (`string, required`): Execution price as a decimal string.
- `fills.sz` (`string, required`): Executed size as a decimal string.
- `fills.side` (`string, required`): Native side B or A.
- `fills.time` (`int64, required`): Execution time in Unix milliseconds.
- `fills.hash` (`string, required`): Transaction hash.
- `fills.tid` (`uint64, required`): Within one block, use (coin, tid). Across blocks, include the frame's block_number. Retain account and order identity for individual fills.
- `fills.crossed` (`bool, required`): True when this account was the taker.
- `fills.dir` (`string, required`): Human-readable position direction.
- `fills.start_position` (`string, required`): Signed position immediately before this fill.
- `fills.oid` (`uint64, required`): Filled order identifier.
- `fills.closed_pnl` (`string, required`): Closed profit and loss as a decimal string.
- `fills.fee` (`string, required`): Trading fee as a decimal string.
- `fills.fee_token` (`string, required`): Fee denomination.
- `fills.builder` (`FillBuilder, optional`): Builder attribution; always present on a matched fill from this method.
- `fills.builder.address` (`string, required`): Builder address.
- `fills.builder.fee` (`string, required`): Builder fee charged on this fill.
- `fills.cloid` (`optional string, optional`): Client order identifier when present.
- `fills.twap_id` (`optional uint64, optional`): TWAP identifier when the fill came from a TWAP order.
- `fills.liquidation` (`FillLiquidation, optional`): Liquidation metadata, unset for non-liquidation fills.
- `fills.liquidation.liquidated_user` (`string, required`): Liquidated account address.
- `fills.liquidation.mark_px` (`string, required`): Liquidation mark price.
- `fills.liquidation.method` (`string, required`): Native liquidation method.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
sequence: 1
fills: {
  user: "0x1111111111111111111111111111111111111111"
  coin: "BTC"
  px: "114250.0"
  sz: "0.25"
  side: "B"
  time: 1785736814057
  hash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  tid: 99887766
  crossed: true
  dir: "Open Long"
  start_position: "0.0"
  oid: 123456789
  closed_pnl: "0.0"
  fee: "0.285625"
  fee_token: "USDC"
  builder: { address: "0x2222222222222222222222222222222222222222" fee: "0.01" }
  cloid: "0x00112233445566778899aabbccddeeff"
  twap_id: 778899
  liquidation: { liquidated_user: "0x3333333333333333333333333333333333333333" mark_px: "114200.0" method: "market" }
}
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: The required builder or a coin entry is malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: Live fills are not currently available.

### Lost live fills

- Code: `ABORTED`
- Description: Frame loss or a stream state reset ended this live-only stream.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require contiguous `sequence` values. A gap or `ABORTED` means live frames were lost; reconnect and use [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) or [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data) for the missing interval. See the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for shared errors.

Related references: [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills) and [StreamUserFills](https://www.dwellir.com/docs/hyperliquid/stream_user_fills).

---

## StreamCandle - Stream Live OHLCV Candles

# StreamCandle - Stream Live OHLCV Candles

`StreamCandle` sends live snapshots of one epoch-aligned OHLCV bucket for a `(coin, interval)` pair. It is a live view, not the historical candle product.

## Request and opening behavior

Both `coin` and `interval` are required. Supported intervals are `1s`, `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, and `1d`.

If the gateway already tracks the bucket, its current state arrives immediately. A cold subscription waits for the next execution, so its first bucket can be partial. Buckets are sparse: no execution means no frame. A new `open_time` signals rollover, and the previous bucket's final frame is sent first.

## Request Parameters

- `coin` (`string, required`): One case-sensitive native coin identifier, validated against the enabled market universe.
- `interval` (`string, required`): One of the 12 fixed-width intervals: 1s, 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, or 1d.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamCandle(ctx, &pb.CandleRequest{Coin: "BTC", Interval: "1m"})
    if err != nil {
        log.Fatal(err)
    }
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("coin=%s interval=%s open_time=%d OHLC=%s/%s/%s/%s volume=%s trades=%d", update.GetCoin(), update.GetInterval(), update.GetOpenTime(), update.GetOpen(), update.GetHigh(), update.GetLow(), update.GetClose(), update.GetVolume(), update.GetTradeCount())
    }
}
```

## Response Fields

- `coin` (`string, required`): Native coin identifier.
- `interval` (`string, required`): Requested fixed-width interval.
- `open_time` (`int64, required`): Epoch-aligned bucket-open time in Unix milliseconds.
- `close_time` (`int64, required`): Bucket open time plus interval width minus 1 millisecond.
- `open` (`string, required`): First execution price in source order.
- `high` (`string, required`): Highest execution price in the bucket.
- `low` (`string, required`): Lowest execution price in the bucket.
- `close` (`string, required`): Last execution price in source order.
- `volume` (`string, required`): Exact decimal sum of base-unit execution volume.
- `trade_count` (`uint64, required`): Number of executions; one matched pair counts once.

## Successful Response

```protobuf
coin: "BTC"
interval: "1m"
open_time: 1785736800000
close_time: 1785736859999
open: "114200.0"
high: "114275.0"
low: "114190.0"
close: "114250.0"
volume: "18.75"
trade_count: 143
```

## Error Responses

### Invalid request

- Code: `INVALID_ARGUMENT`
- Description: The coin is malformed or unavailable, or interval is not one of the 12 supported values.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: Candle streaming is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested candle view is not ready.

### Stream state reset

- Code: `ABORTED`
- Description: The stream state reset; reconnect to resume live bucket updates.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

Frames with the same `open_time` supersede earlier frames. Subscriber lag is recoverable for an open bucket, although a dropped closing frame can only be inferred from a later `open_time`. `FAILED_PRECONDITION` means candle streaming is unavailable; `ABORTED` means the stream state reset. See the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for shared errors.

Related reference: [Hyperliquid Index candles](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data/candles).

---

## StreamFills - Real-time Fill Streaming

# StreamFills - Real-time Fill Streaming

Stream continuous fill data starting from a position, providing real-time access to order executions on Hyperliquid.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations. See the [copy-trading-bot](https://github.com/dwellir-public/gRPC-code-examples/tree/main/copy-trading-bot) for a production-ready example using `StreamFills`.

## When to Use This Method

`StreamFills` is essential for:

- **Trade Monitoring** - Track order executions in real-time
- **Position Management** - Monitor fills for active trading strategies
- **Settlement Tracking** - Verify order completions and partial fills
- **Analytics & Reporting** - Collect comprehensive trade execution data

## Latency

We measured `StreamFills` on the shared endpoint `api-hyperliquid-mainnet-grpc.n.dwellir.com` from AWS Tokyo (ap-northeast-1) on 2026-10-22. The test ran for 5 minutes and received 4,122 blocks of fills with no errors. Latency is the time from the HyperCore block timestamp to the moment the client receives the fills for that block.

| Percentile | Shared endpoint | Dedicated Tokyo node |
| ---------- | --------------- | -------------------- |
| p50        | 163 ms          | 164 ms               |
| p95        | 194 ms          | 195 ms               |
| p99        | 229 ms          | 228 ms               |

The gap between messages was 68 ms at p50 and 129 ms at p95. Your results depend on where your client runs. Run it in Tokyo for the lowest latency.

Method signature

```protobuf
rpc StreamFills(StreamRequest) returns (stream Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`. Explicit zero is invalid. A positioned call replays from the selected record and then tails live; an empty request tails newly written fills. Set `progress` to opt in to [progress frames](#progress-frames).

```protobuf
position: {
  block_number: 1058646974
}
filter: {
  fields: {
    field: "users"
    op: FILTER_OP_IN
    values: "0x1111111111111111111111111111111111111111"
  }
  fields: {
    field: "coins"
    op: FILTER_OP_IN
    values: "BTC"
  }
}
```

Fills accept `users` and `coins` filters. User matching is case-insensitive, coin matching is case-sensitive, values within a field use OR semantics, and the two fields use AND semantics. Stream records with no matching events are skipped. Each returned `Record` contains optional `block_number` and `timestamp` cursors plus the filtered block envelope in `data`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to tail newly written records.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.
- `progress.interval_ms` (`uint32, optional`): Set progress to opt in to progress frames; leave it unset for none. Longest silence in milliseconds before a progress frame. 0 selects the feed default, currently 20000 within bounds of 10000 to 60000; ListFeeds reports the bounds in FeedInfo.progress.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamFills
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_fills_by_block, with non-matching events removed when a filter is applied.
- `progress` (`StreamProgress, optional`): Set only on progress frames, which leave data, block_number, and timestamp unset. Check it before decoding data.
- `progress.scanned_through.block_number` (`int64, optional`): Inclusive cursor of the newest block the stream examined, sent or removed by the filter. A valid resume position; unset until the stream has examined a record.
- `progress.timestamp` (`optional int64, optional`): Source time at scanned_through in Unix milliseconds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Invalid progress request

- Code: `INVALID_ARGUMENT`
- Description: A nonzero progress.interval_ms is outside the bounds advertised in FeedInfo.progress.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Replay capacity is temporarily unavailable; retry with backoff.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Progress frames do not reset the timeout. Reconnect from the last cursor received.

#### Records lost

- Code: `DATA_LOSS`
- Description: The stream lost records, for example because it fell behind the live feed. It ends before sending any cursor past them; reconnect from the last cursor received to re-read the gap.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamFills
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockFills wrapper.

### Successful Response

```protobuf
message BlockFills {
  bytes data = 1;
}
```

```protobuf
rpc StreamFills(Position) returns (stream BlockFills) {}
```

V2 accepts the inclusive cursor fields `block_height` and `timestamp_ms`; an empty `Position` tails new fills. It returns the source JSON in `BlockFills.data`.

## Response Stream

V3 carries the JSON-encoded fills envelope in `Record.data`.

V2 carries the JSON-encoded fills envelope in `BlockFills.data`.

Decode the `data` field to access:

- Fill execution details (price, size, side)
- Order identifiers (order ID, client order ID)
- Counterparty information
- Timestamp and block reference

## Full Fill Spec

`StreamFills` emits a JSON payload matching Hyperliquid's `node_fills` format. Below is the exact structure.

Top-level keys (always present):

```json
{
  "local_time": "2025-07-27T08:50:10.334741319",   // ISO-8601 timestamp when node processed fill (nanosecond precision)
  "block_time": "2025-07-27T08:50:10.273720809",   // ISO-8601 timestamp from block consensus
  "block_number": 676607012,                        // Block height containing this fill
  "events": [                                       // Array of [address, fill_data] pairs
    [
      "0x7839e2f2c375dd2935193f2736167514efff9916",  // User address (40 hex chars, lowercase)
      {
        "coin": "BTC",                              // Trading pair symbol
        "px": "118136.0",                           // Fill price (string)
        "sz": "0.00009",                            // Fill size (string)
        "side": "B",                                // "B" (buy) or "A" (sell/ask)
        "time": 1753606210273,                      // Fill timestamp (ms since Unix epoch)
        "startPosition": "-1.41864",                // Position size before fill (string)
        "dir": "Close Short",                       // Direction: "Open Long" | "Open Short" | "Close Long" | "Close Short"
        "closedPnl": "-0.003753",                   // Realized PnL from closing position (string, can be negative)
        "hash": "0xe7822040155eaa2e737e042854342401120052bbf063906ce8c8f3babe853a79",  // Transaction hash (64 hex)
        "oid": 121670079265,                        // Order ID (numeric)
        "crossed": false,                           // Whether order crossed the spread
        "fee": "-0.000212",                         // Trading fee (string, negative = rebate)
        "tid": 161270588369408,                     // Trade ID; not globally unique
        "cloid": "0x09367b9f8541c581f95b02aaf05f1508",  // Client order ID (optional, 32 hex)
        "feeToken": "USDC",                         // Token used for fee payment
        "twapId": null,                             // TWAP order ID (optional, null if not a TWAP fill)
        "liquidation": null,                        // Liquidation details (optional, null for normal fills)
        "builder": "0x49ae63056b3a0be0b166813ee687309ab653c07c",  // Builder address (optional)
        "builderFee": "0.005528"                    // Builder fee amount (optional, string)
      }
    ]
    // ... more [address, fill_data] pairs
  ]
}
```

Fill event entry (`events[i]`):

```jsonc
[
  "0x...",  // user_address - the trader's address
  {
    // Fill details object
  }
]
```

Fill details fields:

| Field           | Type        | Description                                                                                                                        |
| --------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `coin`          | string      | Trading pair symbol (e.g., "BTC", "ETH", "SOL")                                                                                    |
| `px`            | string      | Fill price                                                                                                                         |
| `sz`            | string      | Fill size                                                                                                                          |
| `side`          | string      | `"B"` for buy, `"A"` for sell                                                                                                      |
| `time`          | number      | Fill timestamp in milliseconds since Unix epoch                                                                                    |
| `startPosition` | string      | Position size before this fill                                                                                                     |
| `dir`           | string      | Position direction: `"Open Long"`, `"Open Short"`, `"Close Long"`, `"Close Short"`                                                 |
| `closedPnl`     | string      | Realized PnL if closing a position (can be negative)                                                                               |
| `hash`          | string      | Transaction hash (64 hex characters)                                                                                               |
| `oid`           | number      | Order ID assigned by the system                                                                                                    |
| `crossed`       | boolean     | Maker/taker indicator. `true` = taker (crossed the spread), `false` = maker (resting order). See [Maker vs Taker](#maker-vs-taker) |
| `fee`           | string      | Trading fee (negative values indicate rebates)                                                                                     |
| `tid`           | number      | Trade ID. Within one block, group matches by `(coin, tid)`. Across blocks, include block identity.                                 |
| `cloid`         | string      | Client order ID if provided (optional)                                                                                             |
| `feeToken`      | string      | Token used for fee payment                                                                                                         |
| `twapId`        | number/null | TWAP order ID if the fill is part of a TWAP execution (optional)                                                                   |
| `liquidation`   | object/null | Liquidation details, present only when the fill is part of a forced position closure. See [Liquidation Data](#liquidation-data)    |
| `builder`       | string      | Builder address if order was routed through a builder (optional)                                                                   |
| `builderFee`    | string      | Fee paid to builder (optional)                                                                                                     |

Guarantees and alignment:

- `events` array contains all fills from the block for all users.
- Each event pairs a user address with their fill details.
- `block_number` is sequential and does not correspond to the potentially skipping `abci_block.round` consensus value in StreamBlocks.
- `block_time` aligns with `abci_block.time` in StreamBlocks.
- Multiple fills per block are delivered in a single message.

The `(coin, tid)` grouping applies within one block. Across blocks, include `block_number` or `block_time` in the match key.
Hyperliquid documents `(block_time, coin, tid)` as the [globally unique trade identity](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions).

Developer tips:

- Within one block, group a match by `(coin, tid)`. Across blocks, include `block_number` or `block_time`. Retain account and order identity when deduplicating individual fills.
- Track `startPosition` and `dir` to reconstruct position changes.
- Sum `closedPnl` across fills to calculate realized PnL.
- Normalize `px`, `sz`, `fee`, and `closedPnl` (strings) to numeric types as appropriate.
- Handle optional fields (`cloid`, `twapId`, `liquidation`, `builder`, `builderFee`) defensively.
- Check `liquidation` to detect forced position closures. See [Liquidation Data](#liquidation-data).
- Use `crossed` to determine maker/taker status. See [Maker vs Taker](#maker-vs-taker).

## Liquidation Data

Liquidation events are embedded within the fills stream. When a fill is part of a forced position closure, the `liquidation` field is present on the fill object.

A liquidation match includes:

1. One **liquidated-side fill** for the forced position close
2. One or more **maker/counterparty fills** for the resting liquidity that absorbed it

Multiple makers can participate in one match. Within one block, group its fills by `(coin, tid)`. Across blocks, include `block_number` or `block_time` in the match key.

A transaction hash can contain more than one match. To identify the actual liquidated user rather than a counterparty, check that:

- `liquidation` is present on the fill
- `dir` contains `"Close"` (e.g., `"Close Long"`, `"Close Short"`)
- The user address matches `liquidation.liquidatedUser`

### Liquidation Object Fields

| Field            | Type   | Description                                    |
| ---------------- | ------ | ---------------------------------------------- |
| `liquidatedUser` | string | Address of the user being liquidated           |
| `markPx`         | string | Mark price at the time of liquidation          |
| `method`         | string | Liquidation method: `"market"` or `"backstop"` |

### Liquidation Methods

| Method     | Description                                                              |
| ---------- | ------------------------------------------------------------------------ |
| `market`   | Standard liquidation filled against resting orders on the book           |
| `backstop` | Backstop liquidation used when the order book cannot absorb the position |

### Example: Single-maker liquidation fill

This example contains one liquidated-side fill and one maker fill. Within that block, a multi-maker liquidation contains additional maker fills with the same `(coin, tid)` match key.

```json
{
  "block_number": 859864054,
  "block_time": "2026-04-16T14:22:31.456000Z",
  "events": [
    [
      "0x7a3b1c9d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b",
      {
        "coin": "BTC",
        "px": "103850.0",
        "sz": "0.0234",
        "side": "A",
        "time": 1744813351456,
        "startPosition": "0.0234",
        "dir": "Close Long",
        "closedPnl": "-31.599",
        "hash": "0xab12cd34ef56ab12cd34ef56ab12cd34ef56ab12cd34ef56ab12cd34ef56ab12",
        "oid": 199445678901,
        "crossed": true,
        "fee": "0.073107",
        "tid": 884916789012345,
        "cloid": null,
        "feeToken": "USDC",
        "twapId": null,
        "liquidation": {
          "liquidatedUser": "0x7a3b1c9d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b",
          "markPx": "103842.5",
          "method": "market"
        }
      }
    ],
    [
      "0x1234abcd5678ef901234abcd5678ef901234abcd",
      {
        "coin": "BTC",
        "px": "103850.0",
        "sz": "0.0234",
        "side": "B",
        "time": 1744813351456,
        "startPosition": "-0.125",
        "dir": "Close Short",
        "closedPnl": "2.457",
        "hash": "0xab12cd34ef56ab12cd34ef56ab12cd34ef56ab12cd34ef56ab12cd34ef56ab12",
        "oid": 199445678902,
        "crossed": false,
        "fee": "-0.007311",
        "tid": 884916789012345,
        "cloid": "0x00000000000003849201784629103847",
        "feeToken": "USDC",
        "twapId": null,
        "liquidation": {
          "liquidatedUser": "0x7a3b1c9d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b",
          "markPx": "103842.5",
          "method": "market"
        }
      }
    ]
  ]
}
```

In this example:

- The first fill (`0x7a3b1c9d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b`) is the **liquidated user** — `dir` is `"Close Long"` and their address matches `liquidatedUser`
- The second fill (`0x1234abcd5678ef901234abcd5678ef901234abcd`) is one **maker/counterparty** — same `liquidatedUser` but a different address
- The liquidated user has negative `closedPnl` (loss) and positive `fee` (paid fee as taker)
- The counterparty has positive `closedPnl` (profit) and negative `fee` (received rebate as maker)

## Maker vs Taker

The `crossed` field on every fill directly indicates maker or taker status:

| `crossed` | Role      | Meaning                                                                                       |
| --------- | --------- | --------------------------------------------------------------------------------------------- |
| `true`    | **Taker** | The order crossed the spread — it matched immediately against a resting order                 |
| `false`   | **Maker** | The order was resting on the book — it provided liquidity and was filled by an incoming order |

### Fee as a Secondary Signal

The `fee` field corroborates the maker/taker role:

| Fee sign                       | Role                      | Example                                |
| ------------------------------ | ------------------------- | -------------------------------------- |
| Positive (e.g., `"0.073107"`)  | Taker — paid a fee        | `"crossed": true, "fee": "0.073107"`   |
| Negative (e.g., `"-0.007311"`) | Maker — received a rebate | `"crossed": false, "fee": "-0.007311"` |

### Matching Both Sides of a Trade

A match contains one taker-side fill and one or more maker-side fills. Multiple makers can satisfy one taker, so do not assume an exactly two-fill buyer/seller pair.

Within one block, group all sides by `(coin, tid)`. Across blocks, include `block_number` or `block_time` in the match key. A transaction hash alone can cover multiple matches.

### Liquidation Fills and Maker/Taker

For book-absorbed liquidation fills, the liquidated-side fill is the **taker** (`crossed: true`) and one or more counterparties whose resting orders are filled are **makers** (`crossed: false`). Preserve every maker fill in a multi-maker match.

| Party                | `crossed` | `fee`                      | Role                              |
| -------------------- | --------- | -------------------------- | --------------------------------- |
| Liquidated user      | `true`    | Positive (pays fee)        | Taker — forced market order       |
| Maker/counterparties | `false`   | Negative (receives rebate) | One or more resting orders filled |

## Common Use Cases

### 1. Trade Execution Tracker

```javascript
class TradeExecutionTracker {
    constructor(streamManager) {
        this.streamManager = streamManager;
        this.executedTrades = new Map();

        streamManager.on('fill', (fillData) => {
            this.processFill(fillData);
        });
    }

    processFill(fillData) {
        // Track each fill by order ID
        const orderId = fillData.oid;

        if (!this.executedTrades.has(orderId)) {
            this.executedTrades.set(orderId, {
                orderId,
                fills: [],
                totalFilled: 0,
                avgPrice: 0
            });
        }

        const trade = this.executedTrades.get(orderId);
        trade.fills.push(fillData);
        trade.totalFilled += parseFloat(fillData.sz);

        // Recalculate average price
        const totalValue = trade.fills.reduce(
            (sum, f) => sum + parseFloat(f.px) * parseFloat(f.sz), 0
        );
        trade.avgPrice = totalValue / trade.totalFilled;

        console.log(`Order ${orderId}: Filled ${trade.totalFilled} @ avg ${trade.avgPrice}`);
    }
}
```

### 2. Fill Rate Monitor

```python
class FillRateMonitor:
    def __init__(self):
        self.fills_per_minute = []
        self.current_minute_fills = 0
        self.last_minute = None

    def record_fill(self, fill_data):
        """Record a fill and track rates"""
        from datetime import datetime

        current_minute = datetime.now().replace(second=0, microsecond=0)

        if self.last_minute != current_minute:
            if self.last_minute is not None:
                self.fills_per_minute.append({
                    'minute': self.last_minute,
                    'count': self.current_minute_fills
                })
            self.last_minute = current_minute
            self.current_minute_fills = 0

        self.current_minute_fills += 1

    def get_average_rate(self, minutes=5):
        """Get average fills per minute over last N minutes"""
        recent = self.fills_per_minute[-minutes:]
        if not recent:
            return 0
        return sum(r['count'] for r in recent) / len(recent)
```

### 3. Position Reconciliation

Open the V3 stream with an empty `StreamRequest` to tail newly written fills, or set `StreamRequest.position.block_number` to replay inclusively. Decode each `Record.data` envelope and apply every fill in its `events` array before persisting the returned cursor.

```go
type PositionReconciler struct {
    client pb.HyperliquidL1GatewayClient
    positions map[string]float64
}

func (pr *PositionReconciler) ReconcileFills(ctx context.Context) {
    stream, err := pr.client.StreamFills(ctx, &pb.Position{})
    if err != nil {
        log.Fatal(err)
    }

    for {
        fill, err := stream.Recv()
        if err != nil {
            log.Printf("Stream error: %v", err)
            return
        }

        pr.updatePosition(fill.Data)
    }
}

func (pr *PositionReconciler) updatePosition(data []byte) {
    var fillData map[string]interface{}
    json.Unmarshal(data, &fillData)

    // Extract fill details and update position
    if coin, ok := fillData["coin"].(string); ok {
        size, _ := fillData["sz"].(float64)
        side, _ := fillData["side"].(string)

        if side == "B" {
            pr.positions[coin] += size
        } else {
            pr.positions[coin] -= size
        }

        log.Printf("Position %s: %f", coin, pr.positions[coin])
    }
}
```

## Progress Frames

Progress frames are an application-level heartbeat. Set `StreamRequest.progress` to receive one after each interval of silence. A `users` or `coins` filter can leave the stream silent for minutes. They keep it open through idle-limited proxies, which HTTP/2 keepalive pings do not, and advance your resume cursor through blocks the filter removed.

A progress frame sets `Record.progress.scanned_through.block_number` and leaves the data fields unset, so check `progress` before decoding `data`. Persist `scanned_through` as an inclusive resume cursor. See [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) for the full contract.

V2 streams do not send progress frames. Use the V3 method to opt in.

## Error Handling and Reconnection

```javascript
class RobustFillStreamer {
    constructor(endpoint) {
        this.endpoint = endpoint;
        this.maxRetries = 5;
        this.retryDelay = 1000;
        this.currentRetries = 0;
    }

    async startStreamWithRetry() {
        while (this.currentRetries < this.maxRetries) {
            try {
                await this.startStream();
                this.currentRetries = 0;
                this.retryDelay = 1000;
            } catch (error) {
                this.currentRetries++;
                console.error(`Stream attempt ${this.currentRetries} failed:`, error.message);

                if (this.currentRetries >= this.maxRetries) {
                    throw new Error('Max retry attempts exceeded');
                }

                // Exponential backoff
                await this.sleep(this.retryDelay);
                this.retryDelay *= 2;
            }
        }
    }

    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
```

## Best Practices

1. **Connection Management**: Implement robust reconnection logic with exponential backoff
2. **Memory Management**: Use bounded collections for storing recent fills to prevent memory leaks
3. **Performance**: Process fills asynchronously to avoid blocking the stream
4. **Monitoring**: Track stream health and fill rates
5. **Error Recovery**: Handle various error types (network, parsing, processing) gracefully
6. **Resource Cleanup**: Properly close streams and connections on shutdown

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint
- **Unavailable Cursors**: A cursor outside retained history returns `NOT_FOUND`
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[Copy Trading Bot](https://github.com/dwellir-public/gRPC-code-examples/tree/main/copy-trading-bot)** - Uses `StreamFills` to mirror trades in real-time

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamL2Book - Stream L2 Book Snapshots

# StreamL2Book - Stream L2 Book Snapshots

`StreamL2Book` sends an aggregated full L2 book for one coin. It opens with the current book and then sends at most one full snapshot per coalesce window.

## Request and opening behavior

`coin` is required and case-sensitive. Omitted `n_levels` returns 20 levels per side, `1` through `100` selects a bounded depth, and explicit `0` requests full depth when the endpoint supports it. An unsupported full-depth request returns `FAILED_PRECONDITION`. `n_sig_figs` accepts `2` through `5`; `mantissa` is valid only with `n_sig_figs: 5` and must be `2` or `5`. `strict: true` suppresses frames when the aggregated levels are unchanged.

The opening snapshot is registered atomically with the subscription. `bids` are ordered best to worst, as are `asks`, and every frame supersedes the previous one.

## Request Parameters

- `coin` (`string, required`): One case-sensitive native coin identifier; validated against the enabled market universe.
- `n_levels` (`optional uint32, optional`): Omitted means 20 levels per side; 1-100 selects bounded depth; explicit 0 requests full depth when the endpoint supports it.
- `n_sig_figs` (`optional uint32, optional`): Optional price aggregation using 2, 3, 4, or 5 significant figures.
- `mantissa` (`optional uint64, optional`): Optional aggregation mantissa; valid only with n_sig_figs 5 and value 2 or 5.
- `strict` (`optional bool, optional`): When true, suppresses a frame whose aggregated bid and ask levels are unchanged.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "errors"
    "io"
    "log"
    "os"
    "os/signal"
    "syscall"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
    "google.golang.org/protobuf/proto"
)

func main() {
    endpoint := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT")
    apiKey := os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }

    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(
        credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}),
    ))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
    ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamL2Book(ctx, &pb.L2BookRequest{
        Coin:     "BTC",
        NLevels:  proto.Uint32(20),
        NSigFigs: proto.Uint32(5),
        Mantissa: proto.Uint64(5),
        Strict:   proto.Bool(true),
    })
    if err != nil {
        log.Fatal(err)
    }

    for {
        update, err := stream.Recv()
        if errors.Is(err, io.EOF) {
            return
        }
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("coin=%s block=%d bids=%d asks=%d", update.GetCoin(), update.GetBlockNumber(), len(update.GetBids()), len(update.GetAsks()))
    }
}
```

## Response Fields

- `coin` (`string, required`): Native coin identifier for this book.
- `time` (`int64, required`): Frame block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number at the end of the coalesce window.
- `bids` (`repeated L2Level, required`): Aggregated bid levels ordered best to worst.
- `bids.px` (`string, required`): Aggregated price as a decimal string.
- `bids.sz` (`string, required`): Total resting size at this price as a decimal string.
- `bids.n` (`uint32, required`): Number of resting orders aggregated into this level.
- `asks` (`repeated L2Level, required`): Aggregated ask levels ordered best to worst.
- `asks.px` (`string, required`): Aggregated price as a decimal string.
- `asks.sz` (`string, required`): Total resting size at this price as a decimal string.
- `asks.n` (`uint32, required`): Number of resting orders aggregated into this level.

## Successful Response

```protobuf
coin: "BTC"
time: 1785736814057
block_number: 1058646974
bids: { px: "114250.0" sz: "1.35" n: 4 }
asks: { px: "114251.0" sz: "0.82" n: 3 }
```

## Error Responses

### Invalid request

- Code: `INVALID_ARGUMENT`
- Description: The coin or an aggregation parameter is malformed, unsupported, or outside its allowed range.

### Endpoint capability unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the endpoint, or the endpoint does not support a full-depth request.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested order-book view is not ready.

### Stream state reset

- Code: `ABORTED`
- Description: The stream state reset; reconnect for a fresh snapshot.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

`block_number` can skip because the stream coalesces completed windows. Subscriber lag drops obsolete snapshots in-band; the next frame restores current state. `ABORTED` means the stream state reset, while `DEADLINE_EXCEEDED` means the consumer was too slow. See the [shared market-stream contract](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for coin namespaces, common errors, and the live-only subscription model.

Related references: [StreamL2BookDiff](https://www.dwellir.com/docs/hyperliquid/stream_l2_book_diff), [StreamBbo](https://www.dwellir.com/docs/hyperliquid/stream_bbo), and the [Order Book WebSocket L2 book](https://www.dwellir.com/docs/hyperliquid/l2-book).

---

## StreamL2BookDiff - Stream Ordered L2 Diffs

# StreamL2BookDiff - Stream Ordered L2 Diffs

`StreamL2BookDiff` carries aggregated L2 level changes for multiple coins. It is the bandwidth-efficient state-reconstruction counterpart to full `StreamL2Book` snapshots.

## Request and opening behavior

`coins` is required and accepts `1` through `20` distinct, case-sensitive identifiers. The depth, significant-figure, and mantissa rules match `StreamL2Book`; there is no `strict` field because unchanged windows emit no diff.

The stream opens with one `snapshot: true` full-book entry per coin, each with `seq: 1` and `prev_seq: 0`. Later entries contain changed levels only. A level whose `sz` is `"0.0"` removes that price.

## Request Parameters

- `coins` (`repeated string, required`): One to 20 distinct, case-sensitive native coin identifiers; duplicates are ignored before applying the cap.
- `n_levels` (`optional uint32, optional`): Omitted means 20 levels per side; 1-100 selects bounded depth; explicit 0 requests full depth when the endpoint supports it.
- `n_sig_figs` (`optional uint32, optional`): Optional price aggregation using 2, 3, 4, or 5 significant figures.
- `mantissa` (`optional uint64, optional`): Optional aggregation mantissa; valid only with n_sig_figs 5 and value 2 or 5.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "errors"
    "io"
    "log"
    "os"
    "os/signal"
    "syscall"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
    "google.golang.org/protobuf/proto"
)

func main() {
    endpoint := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT")
    apiKey := os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
    ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamL2BookDiff(ctx, &pb.L2BookDiffRequest{
        Coins:     []string{"BTC", "ETH"},
        NLevels:   proto.Uint32(20),
        NSigFigs:  proto.Uint32(5),
        Mantissa:  proto.Uint64(5),
    })
    if err != nil {
        log.Fatal(err)
    }

    last := make(map[string]uint64)
    for {
        update, err := stream.Recv()
        if errors.Is(err, io.EOF) {
            return
        }
        if err != nil {
            log.Fatal(err)
        }
        for _, diff := range update.GetDiffs() {
            if previous, ok := last[diff.GetCoin()]; ok && diff.GetPrevSeq() != previous {
                log.Fatalf("gap for %s: prev_seq=%d expected=%d", diff.GetCoin(), diff.GetPrevSeq(), previous)
            }
            if !diff.GetSnapshot() && diff.GetSeq() != diff.GetPrevSeq()+1 {
                log.Fatalf("non-contiguous sequence for %s: seq=%d prev_seq=%d", diff.GetCoin(), diff.GetSeq(), diff.GetPrevSeq())
            }
            last[diff.GetCoin()] = diff.GetSeq()
            log.Printf("coin=%s snapshot=%t seq=%d bids=%d asks=%d", diff.GetCoin(), diff.GetSnapshot(), diff.GetSeq(), len(diff.GetBids()), len(diff.GetAsks()))
        }
    }
}
```

## Response Fields

- `time` (`int64, required`): Coalesce-window block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number at the end of the window.
- `diffs` (`repeated L2CoinDiff, required`): Per-coin snapshots or changed levels; unchanged coins are omitted.
- `diffs.coin` (`string, required`): Coin whose derived book changed.
- `diffs.seq` (`uint64, required`): Per-coin monotonic sequence, starting at 1 on the snapshot.
- `diffs.prev_seq` (`uint64, required`): Previous entry's seq for this coin, or 0 on the snapshot.
- `diffs.bids` (`repeated L2Level, required`): Full bid side on a snapshot, otherwise changed bid levels.
- `diffs.bids.px` (`string, required`): Aggregated price as a decimal string.
- `diffs.bids.sz` (`string, required`): Current size, or 0.0 to remove this level.
- `diffs.bids.n` (`uint32, required`): Resting order count, or 0 on a removed level.
- `diffs.asks` (`repeated L2Level, required`): Full ask side on a snapshot, otherwise changed ask levels.
- `diffs.asks.px` (`string, required`): Aggregated price as a decimal string.
- `diffs.asks.sz` (`string, required`): Current size, or 0.0 to remove this level.
- `diffs.asks.n` (`uint32, required`): Resting order count, or 0 on a removed level.
- `diffs.snapshot` (`bool, required`): True when bids and asks contain the complete book and local state must be rebuilt.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
diffs: {
  coin: "BTC"
  seq: 1
  prev_seq: 0
  bids: { px: "114250.0" sz: "1.35" n: 4 }
  asks: { px: "114251.0" sz: "0.82" n: 3 }
  snapshot: true
}
```

## Error Responses

### Invalid request

- Code: `INVALID_ARGUMENT`
- Description: The coin list or an aggregation parameter is malformed, unsupported, or outside its allowed range.

### Endpoint capability unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the endpoint, or the endpoint does not support a full-depth request.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested order-book view is not ready.

### Lost incremental frames

- Code: `ABORTED`
- Description: Frame loss or a stream state reset broke the diff chain; reconnect and rebuild from opening snapshots.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Track `seq` independently per coin and require every `prev_seq` to equal the last accepted `seq`. A mismatch is loss. Subscriber lag closes the stream with `ABORTED`; reconnect and rebuild every coin from the new opening snapshots. Quiet coins do not advance and unchanged windows produce no frame. See the [shared market-stream contract](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for common request and error rules.

Related references: [StreamL2Book](https://www.dwellir.com/docs/hyperliquid/stream_l2_book) and [StreamRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs).

---

## StreamL4Book - Stream Full L4 Order Book

# StreamL4Book - Stream Full L4 Order Book

`StreamL4Book` exposes the full per-order book for one coin. The first frame is a typed snapshot; later frames carry the node-native JSON diff object in `data`.

## Request and opening behavior

`coin` is required and validated case-sensitively. Omitted `mirror` defaults to `true`, enabling HIP-4 binary-sibling projection. Mirrored orders set `synthetic: true` and have bit 52 set in `oid`.

The snapshot contains typed `L4Order` rows. Each later `diff` contains JSON-encoded `{order_statuses, book_diffs}` plus its block time and sequential block number.

The opening snapshot can exceed the client inbound message limit. The Go example sets a 64 MiB receive allowance as a practical starting point; tune it for the selected coin and workload while keeping memory use bounded.

## Request Parameters

- `coin` (`string, required`): One case-sensitive native coin identifier, validated against the enabled market universe.
- `mirror` (`optional bool, optional`): Enables HIP-4 sibling projection; omission defaults to true.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "errors"
    "io"
    "log"
    "os"
    "os/signal"
    "syscall"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
    "google.golang.org/protobuf/proto"
)

func main() {
    endpoint := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT")
    apiKey := os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(
        endpoint,
        grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})),
        grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(64 * 1024 * 1024)),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
    ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamL4Book(ctx, &pb.L4BookRequest{Coin: "BTC", Mirror: proto.Bool(true)})
    if err != nil {
        log.Fatal(err)
    }
    for {
        update, err := stream.Recv()
        if errors.Is(err, io.EOF) {
            return
        }
        if err != nil {
            log.Fatal(err)
        }
        if snapshot := update.GetSnapshot(); snapshot != nil {
            log.Printf("snapshot coin=%s block=%d bids=%d asks=%d", snapshot.GetCoin(), snapshot.GetBlockNumber(), len(snapshot.GetBids()), len(snapshot.GetAsks()))
            continue
        }
        diff := update.GetDiff()
        log.Printf("diff block=%d json_bytes=%d", diff.GetBlockNumber(), len(diff.GetData()))
    }
}
```

## Response Fields

- `snapshot` (`L4BookSnapshot, optional`): Opening branch of the update oneof; contains the complete typed L4 book.
- `snapshot.coin` (`string, required`): Native coin identifier.
- `snapshot.time` (`int64, required`): Snapshot block time in Unix milliseconds.
- `snapshot.block_number` (`int64, required`): Sequential Hyperliquid block number.
- `snapshot.bids` (`repeated L4Order, required`): Resting bid orders, highest price first.
- `snapshot.bids.user` (`string, required`): Owner address.
- `snapshot.bids.coin` (`string, required`): Native coin identifier.
- `snapshot.bids.side` (`string, required`): Native side B or A.
- `snapshot.bids.limit_px` (`string, required`): Limit price as a decimal string.
- `snapshot.bids.sz` (`string, required`): Resting size as a decimal string.
- `snapshot.bids.oid` (`uint64, required`): Order identifier; synthetic mirror orders have bit 52 set.
- `snapshot.bids.timestamp` (`int64, required`): Order placement time in Unix milliseconds.
- `snapshot.bids.trigger_condition` (`string, required`): Native trigger condition.
- `snapshot.bids.is_trigger` (`bool, required`): Whether this is a trigger order.
- `snapshot.bids.trigger_px` (`string, required`): Trigger price as a decimal string.
- `snapshot.bids.is_position_tpsl` (`bool, required`): Whether this is position-level TP/SL.
- `snapshot.bids.reduce_only` (`bool, required`): Whether the order is reduce-only.
- `snapshot.bids.order_type` (`string, required`): Native order type.
- `snapshot.bids.tif` (`optional string, optional`): Time-in-force value when present.
- `snapshot.bids.cloid` (`optional string, optional`): Client order identifier when present.
- `snapshot.bids.synthetic` (`bool, required`): True only for a synthesized HIP-4 mirror order.
- `snapshot.asks` (`repeated L4Order, required`): Resting ask orders, lowest price first.
- `snapshot.asks.user` (`string, required`): Owner address.
- `snapshot.asks.coin` (`string, required`): Native coin identifier.
- `snapshot.asks.side` (`string, required`): Native side B or A.
- `snapshot.asks.limit_px` (`string, required`): Limit price as a decimal string.
- `snapshot.asks.sz` (`string, required`): Resting size as a decimal string.
- `snapshot.asks.oid` (`uint64, required`): Order identifier; synthetic mirror orders have bit 52 set.
- `snapshot.asks.timestamp` (`int64, required`): Order placement time in Unix milliseconds.
- `snapshot.asks.trigger_condition` (`string, required`): Native trigger condition.
- `snapshot.asks.is_trigger` (`bool, required`): Whether this is a trigger order.
- `snapshot.asks.trigger_px` (`string, required`): Trigger price as a decimal string.
- `snapshot.asks.is_position_tpsl` (`bool, required`): Whether this is position-level TP/SL.
- `snapshot.asks.reduce_only` (`bool, required`): Whether the order is reduce-only.
- `snapshot.asks.order_type` (`string, required`): Native order type.
- `snapshot.asks.tif` (`optional string, optional`): Time-in-force value when present.
- `snapshot.asks.cloid` (`optional string, optional`): Client order identifier when present.
- `snapshot.asks.synthetic` (`bool, required`): True only for a synthesized HIP-4 mirror order.
- `diff` (`L4BookDiff, optional`): Post-snapshot branch of the update oneof; carries one node-native per-block diff.
- `diff.time` (`int64, required`): Diff block time in Unix milliseconds.
- `diff.block_number` (`int64, required`): Sequential Hyperliquid block number.
- `diff.data` (`bytes, required`): JSON-encoded object containing order_statuses and book_diffs.

## Successful Response

```protobuf
snapshot: {
  coin: "BTC"
  time: 1785736814057
  block_number: 1058646974
  bids: {
    user: "0x1111111111111111111111111111111111111111"
    coin: "BTC"
    side: "B"
    limit_px: "114250.0"
    sz: "0.25"
    oid: 123456789
    timestamp: 1785736813000
    trigger_condition: "N/A"
    is_trigger: false
    trigger_px: "0.0"
    is_position_tpsl: false
    reduce_only: false
    order_type: "Limit"
    tif: "Gtc"
    cloid: "0x00112233445566778899aabbccddeeff"
    synthetic: false
  }
}
```

## Error Responses

### Invalid request

- Code: `INVALID_ARGUMENT`
- Description: The required coin is empty, unknown, unavailable, or malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested order-book view is not ready.

### Lost incremental state

- Code: `ABORTED`
- Description: Frame loss, a stream state reset, or a HIP-4 market-shape change requires rebuilding from a new snapshot.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

This is an incremental stream. Frame loss, a stream state reset, or an outcome market changing shape closes it with `ABORTED`. Reconnect and rebuild from the next opening snapshot. For typed order-level diffs without native JSON, use `StreamL4OrderUpdates`. Shared live-stream and error semantics are on the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service).

Related references: [StreamL4OrderUpdates](https://www.dwellir.com/docs/hyperliquid/stream_l4_order_updates) and the [Order Book WebSocket L4 book](https://www.dwellir.com/docs/hyperliquid/l4-book).

---

## StreamL4OrderUpdates - Stream Typed Order Diffs

# StreamL4OrderUpdates - Stream Typed Order Diffs

`StreamL4OrderUpdates` sends typed `NEW`, `UPDATE`, and `REMOVE` changes for the resting L4 book. Apply the diffs directly; this projection has already resolved matching effects.

## Request and opening behavior

An empty `coins` list scopes the subscription to all coins. Explicit coins are deduplicated and validated; blank or `"*"` entries are invalid. Optional `users` filters order owners case-insensitively and combines with `coins` using AND semantics.

The first frame has `snapshot: true`, `sequence: 1`, and `NEW` diffs for every matching resting order. Later frames are block-ordered. A fully filtered frame is still sent with empty `diffs` so the sequence stays contiguous. This stream does not synthesize HIP-4 mirror orders.

## Request Parameters

- `coins` (`repeated string, optional`): Optional exact coin scope; empty means all coins, while blank and wildcard entries are invalid.
- `users` (`repeated string, optional`): Optional 0x-prefixed order-owner addresses matched case-insensitively.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "errors"
    "io"
    "log"
    "os"
    "os/signal"
    "syscall"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT")
    apiKey := os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
    ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamL4OrderUpdates(ctx, &pb.L4OrderUpdatesRequest{
        Coins: []string{"BTC", "ETH"},
        Users: []string{"0x1111111111111111111111111111111111111111"},
    })
    if err != nil {
        log.Fatal(err)
    }

    var last uint64
    for {
        update, err := stream.Recv()
        if errors.Is(err, io.EOF) {
            return
        }
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d snapshot=%t sequence=%d diffs=%d", update.GetBlockNumber(), update.GetSnapshot(), update.GetSequence(), len(update.GetDiffs()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Frame block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `diffs` (`repeated L4OrderDiff, required`): Resting-order changes, or all matching resting orders as NEW entries on the snapshot.
- `diffs.diff_type` (`L4OrderDiffType, required`): NEW, UPDATE, or REMOVE operation.
- `diffs.coin` (`string, required`): Native coin identifier.
- `diffs.oid` (`uint64, required`): Resting order identifier.
- `diffs.user` (`string, required`): Order owner address.
- `diffs.side` (`string, required`): Native side B or A.
- `diffs.px` (`string, required`): Resting price as a decimal string.
- `diffs.sz` (`string, required`): Resting size after the change, or 0.0 on REMOVE.
- `snapshot` (`bool, required`): True on the opening rebuild frame.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the snapshot.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
diffs: {
  diff_type: L4_ORDER_DIFF_TYPE_NEW
  coin: "BTC"
  oid: 123456789
  user: "0x1111111111111111111111111111111111111111"
  side: "B"
  px: "114250.0"
  sz: "0.25"
}
snapshot: true
sequence: 1
```

## Error Responses

### Invalid request

- Code: `INVALID_ARGUMENT`
- Description: A coin or user filter is malformed, or an explicitly listed coin is unavailable.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested order view is not ready.

### Lost incremental frames

- Code: `ABORTED`
- Description: Frame loss or a stream state reset requires reconnecting and rebuilding from a new snapshot.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require each `sequence` to follow the last accepted value. A gap, `ABORTED`, or a stream state reset requires a reconnect and a full rebuild from the new snapshot. Treat an `UPDATE` or `REMOVE` for an unknown `oid` as a no-op. See the [shared market-stream contract](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for common errors.

Related references: [StreamL4Book](https://www.dwellir.com/docs/hyperliquid/stream_l4_book) and [StreamTpslUpdates](https://www.dwellir.com/docs/hyperliquid/stream_tpsl_updates).

---

## StreamLiquidationFills - Stream Liquidation Fills

# StreamLiquidationFills - Stream Liquidation Fills

`StreamLiquidationFills` sends fills that carry liquidation metadata. `liquidated_users` targets `fill.liquidation.liquidated_user`, not the account in `fill.user`.

## Request and live-only behavior

Empty `coins` and `liquidated_users` lists select all liquidation fills. Coins match exactly. Liquidated-user addresses match case-insensitively, and the two filters combine using AND semantics. Unknown coin values simply never match.

The stream has no opening snapshot or backfill. Frames emptied by filtering remain present so the per-subscription `sequence` stays contiguous.

## Request Parameters

- `coins` (`repeated string, optional`): Optional exact coin scope; empty means all coins, and unknown coins simply never match.
- `liquidated_users` (`repeated string, optional`): Optional addresses matched case-insensitively against liquidation.liquidated_user.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamLiquidationFills(ctx, &pb.LiquidationFillsRequest{
        Coins: []string{"BTC", "ETH"},
        LiquidatedUsers: []string{"0x3333333333333333333333333333333333333333"},
    })
    if err != nil {
        log.Fatal(err)
    }
    var last uint64
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d sequence=%d fills=%d", update.GetBlockNumber(), update.GetSequence(), len(update.GetFills()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Source block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the first live frame.
- `fills` (`repeated Fill, required`): Liquidation fills matching the requested liquidated accounts and coins; may be empty after filtering.
- `fills.user` (`string, required`): Account this fill belongs to.
- `fills.coin` (`string, required`): Native coin identifier.
- `fills.px` (`string, required`): Execution price as a decimal string.
- `fills.sz` (`string, required`): Executed size as a decimal string.
- `fills.side` (`string, required`): Native side B or A.
- `fills.time` (`int64, required`): Execution time in Unix milliseconds.
- `fills.hash` (`string, required`): Transaction hash.
- `fills.tid` (`uint64, required`): Within one block, use (coin, tid). Across blocks, include the frame's block_number. Retain account and order identity for individual fills.
- `fills.crossed` (`bool, required`): True when this account was the taker.
- `fills.dir` (`string, required`): Human-readable position direction.
- `fills.start_position` (`string, required`): Signed position immediately before this fill.
- `fills.oid` (`uint64, required`): Filled order identifier.
- `fills.closed_pnl` (`string, required`): Closed profit and loss as a decimal string.
- `fills.fee` (`string, required`): Trading fee as a decimal string.
- `fills.fee_token` (`string, required`): Fee denomination.
- `fills.builder` (`FillBuilder, optional`): Builder attribution, unset for fills without a builder.
- `fills.builder.address` (`string, required`): Builder address.
- `fills.builder.fee` (`string, required`): Builder fee charged on this fill.
- `fills.cloid` (`optional string, optional`): Client order identifier when present.
- `fills.twap_id` (`optional uint64, optional`): TWAP identifier when the fill came from a TWAP order.
- `fills.liquidation` (`FillLiquidation, optional`): Liquidation metadata; always present on a matched fill from this method.
- `fills.liquidation.liquidated_user` (`string, required`): Liquidated account address used by liquidated_users matching.
- `fills.liquidation.mark_px` (`string, required`): Liquidation mark price.
- `fills.liquidation.method` (`string, required`): Native liquidation method.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
sequence: 1
fills: {
  user: "0x1111111111111111111111111111111111111111"
  coin: "BTC"
  px: "114250.0"
  sz: "0.25"
  side: "B"
  time: 1785736814057
  hash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  tid: 99887766
  crossed: true
  dir: "Open Long"
  start_position: "0.0"
  oid: 123456789
  closed_pnl: "0.0"
  fee: "0.285625"
  fee_token: "USDC"
  builder: { address: "0x2222222222222222222222222222222222222222" fee: "0.01" }
  cloid: "0x00112233445566778899aabbccddeeff"
  twap_id: 778899
  liquidation: { liquidated_user: "0x3333333333333333333333333333333333333333" mark_px: "114200.0" method: "market" }
}
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: A coin entry or liquidated-user address is malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: Live fills are not currently available.

### Lost live fills

- Code: `ABORTED`
- Description: Frame loss or a stream state reset ended this live-only stream.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require contiguous `sequence` values. A gap or `ABORTED` means loss; reconnect for live data and recover the missing blocks through [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) or [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data). See the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for shared errors.

Related references: [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills) and [StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades).

---

## StreamMempoolTxs - Stream Pre-Consensus Transactions

# StreamMempoolTxs - Stream Pre-Consensus Transactions

Stream pre-consensus client blocks. A client block is a batch of signed transaction requests that a Hyperliquid node received from its peers before block inclusion. This method is V3-only.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable V3 client setup in Go, Python, and Node.js.

A request in a mempool record is not guaranteed to land in a block. It can still fail, be replaced, be reordered, or never be included. Records carry requests only, with no responses. Use [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) for committed actions and their responses.

We guarantee mempool data availability only in our Tokyo region.

## When to Use This Method

`StreamMempoolTxs` is useful for:

- **Order-flow monitoring** - Observe signed actions before they are committed
- **Inclusion analysis** - Compare pre-consensus requests with committed blocks
- **Latency research** - Measure when requests reach the node relative to block time

## Method signature

```protobuf
rpc StreamMempoolTxs(StreamRequest) returns (stream Record) {}
```

The mempool feed is positioned by time only. Set `position.timestamp` (Unix milliseconds) or `position.timestamp_ns` (Unix nanoseconds); both are inclusive. A positioned call replays from that time and then tails live; an empty request tails newly received client blocks. `position.block_number` returns `INVALID_ARGUMENT`, and so does an explicit zero cursor.

The feed is not filterable. `ListFeeds` advertises no `filter_fields` for `mempool-txs`, so any `filter` constraint returns `INVALID_ARGUMENT`. The feed does not accept `StreamRequest.progress` either; setting it returns `INVALID_ARGUMENT`.

A record carries one whole client block and can exceed the default 4 MiB gRPC receive limit. Raise the client inbound message limit well above the default, for example `grpc.MaxCallRecvMsgSize(64 << 20)` in Go.

## Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive Unix-millisecond receive-time cursor. Several records can share one millisecond. Omit the position to tail newly received client blocks.
- `position.timestamp_ns` (`int64, optional`): Inclusive Unix-nanosecond receive-time cursor; the exact resume cursor for this feed. Explicit zero is invalid.

## Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -max-msg-sz 67108864 \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"timestamp_ns":"1790611197799360275"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamMempoolTxs
```

## Response Fields

- `block_number` (`optional int64, optional`): Always unset. Mempool records are pre-consensus and belong to no block.
- `timestamp` (`optional int64, optional`): Time the node received the client block, in Unix milliseconds.
- `data` (`bytes, required`): The source line as bytes: a JSON array of the receive time and the client block, with its tx_hash and signed_actions.
- `timestamp_ns` (`optional int64, optional`): The receive time in Unix nanoseconds. Resume from it with position.timestamp_ns.

## Successful Response

```protobuf
timestamp: 1790611197799
data: "[\"2026-09-28T15:59:57.799360275\",{\"tx_hash\":\"0x70f7f7919fbb85174223f6c5b957964813a9673f2ccb1d2f85d5a91e8a939c17\",\"signed_actions\":[{\"signature\":{\"r\":\"0x92c15a2df3a6cbe1464903a31abbdcca1ec54edcb6aee1ee0f8805beda05f289\",\"s\":\"0x792fc9397bd81cb8b80f481d8649c4cc1ae683b3113c586e9e8ac98d1fe58280\",\"v\":28},\"action\":{\"type\":\"noop\"},\"nonce\":1790611116331,\"expiresAfter\":1790611227625}]}]"
timestamp_ns: 1790611197799360275
```

## Error Responses

### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, the request sets position.block_number, a nonempty filter, or progress, or a timestamp is more than 2 seconds in the future.

### Not found

- Code: `NOT_FOUND`
- Description: The cursor is before the earliest retained record, or the selected endpoint does not serve the mempool feed.

### Records lost

- Code: `DATA_LOSS`
- Description: The stream fell behind the live feed. Reconnect from the last timestamp_ns to re-read the gap.

### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Reconnect from the last timestamp_ns.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last timestamp_ns.

### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Returned by the server: replay capacity for a positioned stream is temporarily unavailable; retry with backoff.

### Message too large

- Code: `RESOURCE_EXHAUSTED`
- Description: Returned by the client library: a record exceeded its receive limit. Retrying does not help; raise the client inbound message limit and reconnect from the last timestamp_ns.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## Response Stream

Each `Record` carries one client block:

- `block_number` is always unset. Mempool records are pre-consensus and have no block.
- `timestamp` is the time the node received the client block, in Unix milliseconds.
- `timestamp_ns` is the same receive time at nanosecond precision. Only the mempool feed sets it.
- `data` is the source line as bytes. The line is a JSON array, not an object.

## Record Format

Decoded `Record.data` is a two-element array: the receive time, then the client block. Hashes and signatures are truncated below:

```json
["2026-09-28T16:00:01.005217781", {"tx_hash": "0xeb4f...", "signed_actions": [
  {"signature": {"r": "0x1dc1...", "s": "0x161d...", "v": 27},
   "vaultAddress": "0x31ca...",
   "action": {"type": "order", "orders": [{"a": 190, "b": true, "p": "0.040938", "s": "15819", "r": false, "t": {"limit": {"tif": "Alo"}}}], "grouping": "na"},
   "nonce": 1790614526470}
]}]
```

| Field                           | Description                                                                                                                                                                                                       |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `[0]`                           | Receive time in UTC as an ISO-8601 string with nanosecond precision and no `Z` suffix                                                                                                                             |
| `[1].tx_hash`                   | Hash of the client block                                                                                                                                                                                          |
| `[1].signed_actions`            | Signed transaction requests in the client block                                                                                                                                                                   |
| `signed_actions[].action`       | The signed action in the exchange API's action encoding; order actions use the compact `a`/`b`/`p`/`s`/`r`/`t`/`c` keys. See the [action types reference](https://www.dwellir.com/docs/hyperliquid/stream_blocks#action-types-reference) |
| `signed_actions[].signature`    | `r`, `s`, `v` signature components                                                                                                                                                                                |
| `signed_actions[].nonce`        | Action nonce                                                                                                                                                                                                      |
| `signed_actions[].vaultAddress` | Present when the action acts for a vault or subaccount                                                                                                                                                            |
| `signed_actions[].expiresAfter` | Expiry time in Unix milliseconds, when the signer set one                                                                                                                                                         |

Records do not include the signer's address, only the signature (and `vaultAddress` where present), so the feed has no `users` filter.

## Ordering and Delivery

- One `Record` per client block, in the order the node received them. Receive times strictly increased across a 50,000-record sample, but treat that as observed behavior, not a guarantee.
- Several client blocks often share one millisecond. Resuming with `position.timestamp` redelivers every record of that millisecond; deduplicate on `tx_hash` if that matters.
- `timestamp_ns` is the exact cursor. Resuming with `position.timestamp_ns` set to the last received value redelivers exactly that one record, then continues.
- A cursor before the earliest retained record returns `NOT_FOUND`. `timestamp` is compared at millisecond precision, `timestamp_ns` exactly.
- A stream timestamp up to 2 seconds ahead of the server's clock starts a live tail; more than 2 seconds ahead returns `INVALID_ARGUMENT`.

## Error Handling and Reconnection

Persist the last `Record.timestamp_ns` that was set and reconnect with `StreamRequest.position.timestamp_ns` set to it. Replay is inclusive, so skip the one record that matches the saved cursor. A replay can skip a stored record whose timestamp does not parse, without an error.

The feed is high volume: every subscriber receives every client block, several megabytes per second uncompressed. Drain the stream continuously and enable gzip if bandwidth matters.

- **`DATA_LOSS`** - The stream fell behind the live feed and ended before sending any record after the loss. Reconnect from the last `timestamp_ns`; the replay re-reads the gap. A positioned stream that catches up with live data ends the same way if it then falls behind.
- **`UNAVAILABLE`** - No client blocks arrived before the stream timeout, for example while upstream peers are quiet, or the stream failed mid-stream. Reconnect from the last `timestamp_ns`.
- **`DEADLINE_EXCEEDED`** - The stream could not deliver records in time because the client read too slowly or stopped reading. Reconnect from the last `timestamp_ns`.
- **`RESOURCE_EXHAUSTED`** - From the client library, a record exceeded the client [receive limit](#method-signature); raise it before reconnecting, since retrying alone fails again. From the server, replay capacity is temporarily unavailable; retry with backoff.
- **`NOT_FOUND`** - The cursor is outside retained history, or the selected endpoint does not serve the mempool feed. Check `ListFeeds` for `mempool-txs`.

Once replay has caught up with live data, a growing gap between `Record.timestamp` and your clock means the client is not keeping up. Process records faster, or the stream ends with `DATA_LOSS`.

## Current Limitations

- **Pre-consensus only**: Records carry requests without responses, and inclusion is not guaranteed
- **No filtering**: Every subscriber receives every client block
- **Time positioning only**: `position.block_number` is rejected; resume on `timestamp_ns`
- **Replay History**: Available replay history varies by endpoint. A cursor outside retained history returns `NOT_FOUND`

## Resources

- **[GetMempoolTxs](https://www.dwellir.com/docs/hyperliquid/get_mempool_txs)** - Point-in-time mempool record retrieval
- **[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks)** - Committed blocks with signed actions and responses
- **[ListFeeds](https://www.dwellir.com/docs/hyperliquid/list_feeds)** - Feed inventory and accepted cursor kinds

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamMiscEvents - Real-time Miscellaneous Event Streaming

# StreamMiscEvents - Real-time Miscellaneous Event Streaming

Stream miscellaneous L1 events starting from a position, providing real-time access to every non-fill balance-affecting action on Hyperliquid: deposits, withdrawals, transfers, staking delegations, and validator rewards.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`StreamMiscEvents` is essential for:

- **Deposit & Withdrawal Monitoring** - Track funds entering and leaving accounts in real-time
- **Treasury & Transfer Tracking** - Follow spot transfers and internal `send` movements
- **Staking & Delegation Analytics** - Observe delegations, undelegations, and staking withdrawals
- **Validator Reward Accounting** - Reconcile per-epoch validator reward distributions
- **Compliance & Audit Trails** - Build a complete record of balance-affecting activity

`StreamMiscEvents` covers everything `StreamFills` does not. Fills are trades; misc events are every other action that moves funds. Consume both streams together for a complete view of all balance-affecting activity.

Method signature

```protobuf
rpc StreamMiscEvents(StreamRequest) returns (stream Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`. Explicit zero is invalid. A positioned call replays inclusively and then tails live; an empty request tails newly written miscellaneous events. Set `progress` to opt in to [progress frames](#progress-frames).

```protobuf
position: {
  block_number: 1058646974
}
filter: {
  fields: {
    field: "users"
    op: FILTER_OP_IN
    values: "0x1111111111111111111111111111111111111111"
  }
}
```

Miscellaneous events accept a `users` filter. User matching is case-insensitive, and values within the field use OR semantics. This feed does not accept `coins`. Stream records with no matching events are skipped. Each returned `Record` contains optional `block_number` and `timestamp` cursors plus the filtered block envelope in `data`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to tail newly written records.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users constraints. Values within the field OR together. This feed does not accept coins.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name. This feed accepts users only.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.
- `progress.interval_ms` (`uint32, optional`): Set progress to opt in to progress frames; leave it unset for none. Longest silence in milliseconds before a progress frame. 0 selects the feed default, currently 20000 within bounds of 10000 to 60000; ListFeeds reports the bounds in FeedInfo.progress.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"users","op":"FILTER_OP_IN","values":["0x1111111111111111111111111111111111111111"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamMiscEvents
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the misc_events_by_block, with non-matching events removed when a filter is applied.
- `progress` (`StreamProgress, optional`): Set only on progress frames, which leave data, block_number, and timestamp unset. Check it before decoding data.
- `progress.scanned_through.block_number` (`int64, optional`): Inclusive cursor of the newest block the stream examined, sent or removed by the filter. A valid resume position; unset until the stream has examined a record.
- `progress.timestamp` (`optional int64, optional`): Source time at scanned_through in Unix milliseconds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Invalid progress request

- Code: `INVALID_ARGUMENT`
- Description: A nonzero progress.interval_ms is outside the bounds advertised in FeedInfo.progress.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Replay capacity is temporarily unavailable; retry with backoff.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Progress frames do not reset the timeout. Reconnect from the last cursor received.

#### Records lost

- Code: `DATA_LOSS`
- Description: The stream lost records, for example because it fell behind the live feed. It ends before sending any cursor past them; reconnect from the last cursor received to re-read the gap.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamMiscEvents
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockMiscEvents wrapper.

### Successful Response

```protobuf
message BlockMiscEvents {
  bytes data = 1;
}
```

```protobuf
rpc StreamMiscEvents(Position) returns (stream BlockMiscEvents) {}
```

V2 accepts the inclusive cursor fields `block_height` and `timestamp_ms`; an empty `Position` tails new event records. It returns the source JSON in `BlockMiscEvents.data`.

## Response Stream

V3 carries the JSON-encoded `misc_events_by_block` envelope in `Record.data`.

V2 carries the JSON-encoded `misc_events_by_block` envelope in `BlockMiscEvents.data`.

Decode the `data` field to access:

- Block reference (`local_time`, `block_time`, `block_number`)
- An `events` array of miscellaneous L1 event objects (empty for most blocks)

## Per-Block Delivery

An unfiltered source envelope can contain an empty `events` array. That is a valid source record, not a transport heartbeat, and it does not prove that the connection is healthy. A `users` filter skips records with zero matching events, so those empty envelopes are not delivered.

Clients must detect discontinuities and duplicates and persist only a cursor they actually received. Stream health comes from RPC status, deadlines, and reconnect handling; `UNAVAILABLE` means no new records arrived before the stream timeout.

## Full Misc Events Spec

`StreamMiscEvents` emits a JSON payload matching Hyperliquid's `misc_events_by_block` format, passed through byte-for-byte from the node with no normalization. Below is the exact structure.

Top-level keys (always present):

```json
{
  "local_time": "2026-07-02T11:10:49.483839100",   // ISO-8601 timestamp when node processed the block (nanosecond precision)
  "block_time": "2026-07-02T11:10:47.023075863",    // ISO-8601 timestamp from block consensus
  "block_number": 1057659853,                        // Block height containing these events
  "events": []                                       // Array of miscellaneous event objects (empty for most blocks)
}
```

Each entry in `events` is a raw upstream Hyperliquid L1 event object:

| Field   | Type   | Description                                                                                                                                |
| ------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `time`  | string | ISO-8601 timestamp of the event                                                                                                            |
| `hash`  | string | Transaction hash. An all-zeros hash indicates a system-generated event (e.g. validator rewards) rather than a user transaction             |
| `inner` | object | Single-key object whose key is the event type discriminator (e.g. `"LedgerUpdate"`, `"Delegation"`, `"CWithdrawal"`, `"ValidatorRewards"`) |

Branch on the single key inside `inner` to determine the event type. The sections below cover the event types observed on mainnet; the upstream schema defines additional types, so treat these as examples rather than an exhaustive list. The authoritative schema reference is Hyperliquid's [L1 data schemas documentation](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/nodes/l1-data-schemas).

Guarantees and alignment:

- Unfiltered `events` contains all miscellaneous events from the block, across all users.
- A `users` filter keeps only matching events in `events`. See [User filtering](#user-filtering).
- An envelope may contain an empty `events` array; treat it as source data rather than a liveness signal.
- `block_number` is sequential and distinct from the potentially skipping `abci_block.round` consensus value in StreamBlocks; `block_time` aligns with `abci_block.time`.

Developer tips:

- Branch on the key inside `inner` and handle unknown event types defensively — the upstream set can grow.
- Track the last processed `block_number` so you can resume cleanly after a reconnect.
- Normalize amount fields (strings) to numeric types as appropriate.
- Treat the all-zeros `hash` as the marker for system-generated events.

## Event Types

### LedgerUpdate

`LedgerUpdate` is the most common event type. It carries a `users` array (the involved addresses) and a `delta` object whose `type` field discriminates the specific ledger action.

```json
{
  "time": "2026-07-02T11:10:47.023075863",
  "hash": "0xae740acbd26e0108afed043f0a9bcd02022d00b16d611fda523cb61e9161daf3",
  "inner": {
    "LedgerUpdate": {
      "users": [
        "0x2000000000000000000000000000000000000000",
        "0x0a82a35f3e54aede3a20931f446836e6c69cae0b"
      ],
      "delta": {
        "type": "spotTransfer",
        "token": "USDC",
        "amount": "100.058362",
        "usdcValue": "100.058362",
        "user": "0x2000000000000000000000000000000000000000",
        "destination": "0x0a82a35f3e54aede3a20931f446836e6c69cae0b",
        "fee": "0.0",
        "nativeTokenFee": "0.0",
        "nonce": 2053915,
        "feeToken": ""
      }
    }
  }
}
```

The `delta.type` discriminator determines the remaining fields. Observed types on mainnet include:

| `delta.type`   | Meaning                            | Notable fields                                               |
| -------------- | ---------------------------------- | ------------------------------------------------------------ |
| `send`         | Internal transfer between accounts | `user`, `destination`, `token`, `amount`, `usdcValue`, `fee` |
| `spotTransfer` | Spot balance transfer              | `user`, `destination`, `token`, `amount`, `usdcValue`, `fee` |
| `deposit`      | Funds deposited into an account    | `usdc`                                                       |
| `withdraw`     | Funds withdrawn from an account    | `usdc`, `nonce`, `fee`                                       |
| `rewardsClaim` | Rewards claimed                    | `token`, `amount`                                            |
| `borrowLend`   | Borrow/lend operation              | `token`, `operation`, `amount`, `interestAmount`             |

More `delta.type` values exist upstream; branch defensively on `delta.type` and treat this table as examples, not an exhaustive list. Example deltas:

```json
{ "type": "deposit", "usdc": "3494.915745" }
{ "type": "withdraw", "usdc": "89.15", "nonce": 1782990425200000, "fee": "1.0" }
{ "type": "rewardsClaim", "amount": "1.097128", "token": "USDC" }
{ "type": "borrowLend", "token": "USDC", "operation": "supply", "amount": "0.23068", "interestAmount": "0.0" }
```

### Delegation

Staking delegation and undelegation. The `is_undelegate` flag distinguishes the two directions.

```json
{
  "time": "2026-07-02T11:11:06.583481947",
  "hash": "0xfa0716eba98e39b0fb80043f0a9cec02029400d1448158839dcfc23e6882139b",
  "inner": {
    "Delegation": {
      "user": "0xd5a5ae523080973946ac67e34f5fc70671bd8667",
      "validator": "0x5ac99df645f3414876c816caa18b2d234024b487",
      "amount": "20.65611502",
      "is_undelegate": true
    }
  }
}
```

### CWithdrawal

A staking withdrawal, which enters a pending state until finalization. The `is_finalized` flag reflects whether the withdrawal has completed.

```json
{
  "time": "2026-07-02T11:11:07.283636968",
  "hash": "0xae4f651df8ef488eafc9043f0a9cf6021348000393e2676052181070b7e32279",
  "inner": {
    "CWithdrawal": {
      "user": "0xd5a5ae523080973946ac67e34f5fc70671bd8667",
      "amount": "20.65611502",
      "is_finalized": false
    }
  }
}
```

### ValidatorRewards

Per-epoch validator reward distributions. These are system-generated, so they carry an all-zeros `hash`. The `validator_to_reward` array holds `[validator_address, amount]` pairs.

```json
{
  "time": "2026-07-02T11:11:00.042812129",
  "hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "inner": {
    "ValidatorRewards": {
      "validator_to_reward": [
        ["0x000000000056f99d36b6f2e0c51fd41496bbacb8", "0.2806444"],
        ["0x15458aed3c7a49b215fbfa863c6ff550c31e1a31", "0.22056816"],
        ["0x30c66ebc7f5ef4f340b424a26e4d944f60129815", "0.34709989"]
      ]
    }
  }
}
```

## User filtering

A `users` filter keeps an event when any of its user-role addresses is in the request list. Matching is case-insensitive. Validator-role addresses are not matched.

| Event kind                                         | Addresses that match                                                              |
| -------------------------------------------------- | --------------------------------------------------------------------------------- |
| `LedgerUpdate`                                     | `users[]`, plus `delta.user`, `delta.destination`, and `delta.vault` when present |
| `CDeposit`, `CWithdrawal`, `Delegation`            | `user` (not `validator`)                                                          |
| `Funding`                                          | any `deltas[].user`                                                               |
| `ValidatorRewards`, `GossipPriorityAuctionRestart` | none; these never match                                                           |

A `LedgerUpdate` `send` matches the sender and the destination. A `Funding` match returns the whole event, including deltas for other accounts.

`ListFeeds` advertises `users` for this feed. A `coins` field, an empty value list, or an unknown field name returns `INVALID_ARGUMENT`. An unknown `inner` kind fails a filtered call with `INTERNAL`; unfiltered calls still deliver the record.

## Common Use Cases

Open V3 with an empty `StreamRequest` to tail newly written records, decode each `Record.data` envelope, and branch on the event's `inner` discriminator. Pass `filter.fields` with `users` to receive only events that involve those addresses. To resume, set `StreamRequest.position.block_number` to a cursor you persisted and replay inclusively, deduplicating the committed record.

### 1. Deposit and Withdrawal Monitor

```python
def classify_event(event):
    """Return a (kind, detail) tuple for a misc event."""
    inner = event['inner']
    kind = next(iter(inner))          # the single discriminator key
    body = inner[kind]

    if kind == 'LedgerUpdate':
        delta = body['delta']
        return (delta['type'], delta)  # e.g. ('deposit', {...})
    return (kind, body)                # e.g. ('Delegation', {...})

def watch_flows(client, metadata):
    request = hyperliquid_pb2.Position()  # latest
    for response in client.StreamMiscEvents(request, metadata=metadata):
        block = json.loads(response.data)
        for event in block.get('events', []):
            kind, detail = classify_event(event)
            if kind in ('deposit', 'withdraw'):
                print(f"block {block['block_number']}: {kind} {detail.get('usdc')} USDC")
```

### 2. Streaming Misc Events in Python

```python
import grpc
import json
import os
import hyperliquid_pb2
import hyperliquid_pb2_grpc

def stream_misc_events():
    endpoint = os.getenv('HYPERLIQUID_ENDPOINT')
    api_key = os.getenv('API_KEY')

    credentials = grpc.ssl_channel_credentials()
    options = [('grpc.max_receive_message_length', 150 * 1024 * 1024)]  # 150MB max
    metadata = [('x-api-key', api_key)]

    with grpc.secure_channel(endpoint, credentials, options=options) as channel:
        client = hyperliquid_pb2_grpc.HyperliquidL1GatewayStub(channel)

        # Empty Position means latest; set block_height or timestamp_ms to backfill
        request = hyperliquid_pb2.Position()

        for response in client.StreamMiscEvents(request, metadata=metadata):
            block = json.loads(response.data)
            events = block.get('events', [])
            if events:
                print(f"block {block['block_number']}: {len(events)} misc events")
```

## Progress Frames

Progress frames are an application-level heartbeat. Set `StreamRequest.progress` to receive one after each interval of silence. A `users` filter can leave the stream silent for minutes. They keep it open through idle-limited proxies, which HTTP/2 keepalive pings do not, and advance your resume cursor through blocks the filter removed.

A progress frame sets `Record.progress.scanned_through.block_number` and leaves the data fields unset, so check `progress` before decoding `data`. Persist `scanned_through` as an inclusive resume cursor. See [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) for the full contract.

V2 streams do not send progress frames. Use the V3 method to opt in.

## Error Handling and Reconnection

Reconnect with `StreamRequest.position.block_number` set to the last committed V3 cursor, from a data record or a progress frame's `scanned_through`. Replay is inclusive, so deduplicate that record before advancing. Use bounded backoff for retryable RPC statuses.

Reconnect by replaying from the last processed block. Pass the next `block_height` in the `Position` so no events are skipped or double-counted.

```python
def stream_with_resume(client, metadata, start_block):
    next_block = start_block
    while True:
        request = hyperliquid_pb2.Position(block_height=next_block)
        try:
            for response in client.StreamMiscEvents(request, metadata=metadata):
                block = json.loads(response.data)
                process(block)
                next_block = block['block_number'] + 1
        except grpc.RpcError as e:
            print(f"stream error, resuming from {next_block}: {e}")
```

## Best Practices

1. **Connection Management**: Implement robust reconnection logic with exponential backoff
2. **Resumable State**: Follow the version-specific recovery guidance above and persist the cursor required by your selected API version
3. **Defensive Parsing**: Branch on the key inside `inner` (and `delta.type` for `LedgerUpdate`) and handle unknown types gracefully
4. **Health Monitoring**: Use RPC status, deadlines, and reconnect handling; empty source envelopes are not heartbeats
5. **Performance**: Process events asynchronously to avoid blocking the stream
6. **Resource Cleanup**: Properly close streams and connections on shutdown

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Schema Coverage**: The upstream event set can grow; treat the documented event and delta types as examples, not an exhaustive list
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[GetMiscEvents](https://www.dwellir.com/docs/hyperliquid/get_misc_events)** - Point-in-time miscellaneous event retrieval
- **[StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills)** - The sibling stream for trade executions; pair with misc events for complete balance coverage
- **[Hyperliquid L1 Data Schemas](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/nodes/l1-data-schemas)** - Authoritative upstream event schema reference

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamOrderStatuses - Real-time Order Status Streaming

# StreamOrderStatuses - Real-time Order Status Streaming

Stream order status events starting from a position, providing real-time access to the lifecycle of every order on Hyperliquid: opens, fills, cancellations, and rejections.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`StreamOrderStatuses` is essential for:

- **Order Lifecycle Tracking** - Follow an order from open through fill, cancel, or rejection
- **Rejection Analysis** - Identify why orders are rejected using the `status` field
- **Resting-Order Context** - Read the full order object behind each status change
- **Compliance and Auditing** - Record every status transition with block alignment

Method signature

```protobuf
rpc StreamOrderStatuses(StreamRequest) returns (stream Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`. Explicit zero is invalid. A positioned call replays inclusively and then tails live; an empty request tails newly written status records. Set `progress` to opt in to [progress frames](#progress-frames).

```protobuf
filter: {
  fields: {
    field: "users"
    op: FILTER_OP_IN
    values: "0x1111111111111111111111111111111111111111"
  }
}
```

Order statuses accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. Records with zero matching events are skipped. Each `Record` contains optional `block_number` and `timestamp` cursors plus the filtered envelope in `data`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to tail newly written records.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.
- `progress.interval_ms` (`uint32, optional`): Set progress to opt in to progress frames; leave it unset for none. Longest silence in milliseconds before a progress frame. 0 selects the feed default, currently 20000 within bounds of 10000 to 60000; ListFeeds reports the bounds in FeedInfo.progress.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamOrderStatuses
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_order_statuses_by_block, with non-matching events removed when a filter is applied.
- `progress` (`StreamProgress, optional`): Set only on progress frames, which leave data, block_number, and timestamp unset. Check it before decoding data.
- `progress.scanned_through.block_number` (`int64, optional`): Inclusive cursor of the newest block the stream examined, sent or removed by the filter. A valid resume position; unset until the stream has examined a record.
- `progress.timestamp` (`optional int64, optional`): Source time at scanned_through in Unix milliseconds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Invalid progress request

- Code: `INVALID_ARGUMENT`
- Description: A nonzero progress.interval_ms is outside the bounds advertised in FeedInfo.progress.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Replay capacity is temporarily unavailable; retry with backoff.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Progress frames do not reset the timeout. Reconnect from the last cursor received.

#### Records lost

- Code: `DATA_LOSS`
- Description: The stream lost records, for example because it fell behind the live feed. It ends before sending any cursor past them; reconnect from the last cursor received to re-read the gap.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamOrderStatuses
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockOrderStatuses wrapper.

### Successful Response

```protobuf
message BlockOrderStatuses {
  bytes data = 1;
}
```

```protobuf
rpc StreamOrderStatuses(Position) returns (stream BlockOrderStatuses) {}
```

V2 accepts the inclusive cursor fields `block_height` and `timestamp_ms`; an empty `Position` tails new status records. It returns the source JSON in `BlockOrderStatuses.data`.

## Response Stream

V3 carries the JSON-encoded `node_order_statuses_by_block` envelope in `Record.data`.

V2 carries the JSON-encoded `node_order_statuses_by_block` envelope in `BlockOrderStatuses.data`.

Decode the `data` field to access:

- Block reference (`local_time`, `block_time`, `block_number`)
- An `events` array of status records
- A full order object behind each status change

## Full Order Status Spec

`StreamOrderStatuses` emits a JSON payload matching Hyperliquid's `node_order_statuses_by_block` format. The envelope is the same block-envelope shape as fills, but `events` holds status-record objects rather than `[address, fill]` tuples.

Top-level keys (always present):

```json
{
  "local_time": "2026-04-20T00:00:00.040479928",   // ISO-8601 timestamp when node processed the block (nanosecond precision)
  "block_time": "2026-04-19T23:59:59.576040791",    // ISO-8601 timestamp from block consensus
  "block_number": 12345,                            // Block height containing these events
  "events": [                                       // Array of status-record objects
    {
      "time": "2026-04-19T23:59:59.576040791",      // Event timestamp (string, not integer ms)
      "user": "0x1234567890abcdef1234567890abcdef12345678",  // User address
      "hash": "0x00...",                            // Transaction hash (nullable)
      "builder": { "b": "0x00...", "f": 50 },       // Builder address and fee (nullable)
      "status": "open",                             // Status value (see table below)
      "order": { }                                  // Full order object (see Order Object)
    }
  ]
}
```

Status event fields (`events[i]`):

| Field     | Type           | Description                                                                                        |
| --------- | -------------- | -------------------------------------------------------------------------------------------------- |
| `time`    | string         | Event timestamp in the no-`Z` layout. Note: this is a string, **not** an integer millisecond value |
| `user`    | string         | User address                                                                                       |
| `hash`    | string or null | Transaction hash. `null` for some statuses (for example `reduceOnlyCanceled`)                      |
| `builder` | object or null | `{ "b": <address>, "f": <fee> }`, the builder address and fee                                      |
| `status`  | string         | Status value. See [Status Values](#status-values)                                                  |
| `order`   | object         | The resting-order view. See [Order Object](#order-object)                                          |

### Status Values

Observed `status` values (the list is not exhaustive):

| Status                            | Meaning                                     |
| --------------------------------- | ------------------------------------------- |
| `open`                            | Order accepted and resting on the book      |
| `filled`                          | Order filled                                |
| `canceled`                        | Order canceled                              |
| `reduceOnlyCanceled`              | Reduce-only order canceled                  |
| `badAloPxRejected`                | Add-liquidity-only order rejected on price  |
| `insufficientSpotBalanceRejected` | Rejected for insufficient spot balance      |
| `iocCancelRejected`               | Immediate-or-cancel order rejected          |
| `minTradeNtlRejected`             | Rejected for failing minimum trade notional |
| `perpMarginRejected`              | Rejected for insufficient perp margin       |
| `reduceOnlyRejected`              | Reduce-only order rejected                  |
| `selfTradeCanceled`               | Canceled to prevent a self-trade            |

### Order Object

The `order` field is the shared resting-order schema, the same object returned by [GetOrderBookSnapshot](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot).

| Field              | Type           | Description                                                                                                              |
| ------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `coin`             | string         | Coin identifier                                                                                                          |
| `side`             | string         | `"B"` or `"A"`                                                                                                           |
| `limitPx`          | string         | Limit price (numeric string)                                                                                             |
| `sz`               | string         | Current size (numeric string)                                                                                            |
| `oid`              | number         | Order identifier. Not reliably unique across coins. See [Order Identifiers](#order-identifiers)                          |
| `timestamp`        | number         | Order-creation time in Unix milliseconds                                                                                 |
| `triggerCondition` | string         | `"N/A"` for non-trigger orders                                                                                           |
| `isTrigger`        | boolean        | Whether the order is a trigger order                                                                                     |
| `triggerPx`        | string         | `"0.0"` when `isTrigger` is false                                                                                        |
| `children`         | array          | Nested trigger-order schedule. Trigger orders (TP/SL) live here, not as top-level entries. Empty for non-trigger parents |
| `isPositionTpsl`   | boolean        | Whether this is a position-level take-profit / stop-loss                                                                 |
| `reduceOnly`       | boolean        | Whether the order is reduce-only                                                                                         |
| `orderType`        | string         | `"Limit"`, `"Trigger"`, etc.                                                                                             |
| `origSz`           | string         | Original size                                                                                                            |
| `tif`              | string         | Time-in-force, for example `"Alo"`, `"Gtc"`, `"Ioc"`                                                                     |
| `cloid`            | string or null | Client order ID                                                                                                          |

Guarantees and alignment:

- `events` contains all status records from the block, across all coins and users.
- Messages arrive in strictly increasing `block_number`, one per source block (including blocks with an empty `events` array).
- `block_number` is sequential and distinct from the potentially skipping `abci_block.round` consensus value in StreamBlocks; `block_time` aligns with `abci_block.time`.

Developer tips:

- Branch on `status` to track lifecycle transitions and isolate rejections.
- Handle `hash` and `builder` defensively; both can be `null`.
- Treat `time` as a formatted string, distinct from the integer-millisecond `time` on fill events.

## Order Identifiers

`oid` is **not reliably unique across coins**. Consumers that index or join per-order state must key on the `(coin, oid)` tuple, never on `oid` alone.

Outcome markets (HIP-4) demonstrably reuse oids across the two sides of a single market (for example `#30` and `#31`) within one block. Keying on `(coin, oid)` is safe whether or not oids turn out to be globally unique elsewhere.

## Common Use Cases

### 1. Rejection Monitor

```python
REJECTIONS = {
    'badAloPxRejected', 'insufficientSpotBalanceRejected', 'iocCancelRejected',
    'minTradeNtlRejected', 'perpMarginRejected', 'reduceOnlyRejected',
}

def count_rejections(block):
    counts = {}
    for event in block.get('events', []):
        status = event['status']
        if status in REJECTIONS:
            counts[status] = counts.get(status, 0) + 1
    return counts
```

### 2. Streaming Statuses in Python

Open V3 with an empty `StreamRequest` to tail newly written records, or set `StreamRequest.position.block_number` for inclusive replay. Decode each `Record.data` envelope before passing it to the rejection monitor above.

```python
import grpc
import json
import os
import hyperliquid_pb2
import hyperliquid_pb2_grpc

def stream_order_statuses():
    endpoint = os.getenv('HYPERLIQUID_ENDPOINT')
    api_key = os.getenv('API_KEY')

    credentials = grpc.ssl_channel_credentials()
    options = [('grpc.max_receive_message_length', 150 * 1024 * 1024)]  # 150MB max
    metadata = [('x-api-key', api_key)]

    with grpc.secure_channel(endpoint, credentials, options=options) as channel:
        client = hyperliquid_pb2_grpc.HyperliquidL1GatewayStub(channel)

        # Empty Position means latest; set block_height or timestamp_ms to backfill
        request = hyperliquid_pb2.Position()

        for response in client.StreamOrderStatuses(request, metadata=metadata):
            block = json.loads(response.data)
            for event in block.get('events', []):
                print(f"{event['status']:>24}  {event['order']['coin']}  oid={event['order']['oid']}")
```

## Progress Frames

Progress frames are an application-level heartbeat. Set `StreamRequest.progress` to receive one after each interval of silence. A `users` or `coins` filter can leave the stream silent for minutes. They keep it open through idle-limited proxies, which HTTP/2 keepalive pings do not, and advance your resume cursor through blocks the filter removed.

A progress frame sets `Record.progress.scanned_through.block_number` and leaves the data fields unset, so check `progress` before decoding `data`. Persist `scanned_through` as an inclusive resume cursor. See [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) for the full contract.

V2 streams do not send progress frames. Use the V3 method to opt in.

## Error Handling and Reconnection

Reconnect with `StreamRequest.position.block_number` set to the last committed V3 cursor, from a data record or a progress frame's `scanned_through`. Replay is inclusive, so deduplicate that record before advancing.

Reconnect by replaying from the last processed block. Pass the next `block_height` in the `Position` so no events are skipped or duplicated.

```python
def stream_with_resume(client, metadata, start_block):
    next_block = start_block
    while True:
        request = hyperliquid_pb2.Position(block_height=next_block)
        try:
            for response in client.StreamOrderStatuses(request, metadata=metadata):
                block = json.loads(response.data)
                process(block)
                next_block = block['block_number'] + 1
        except grpc.RpcError as e:
            print(f"stream error, resuming from {next_block}: {e}")
```

## Best Practices

1. **Connection Management**: Implement robust reconnection logic with exponential backoff
2. **Resumable State**: Follow the version-specific recovery guidance above and persist the cursor required by your selected API version
3. **Stable Keys**: Index per-order state on `(coin, oid)` to stay correct across coins
4. **Defensive Parsing**: Handle nullable `hash` and `builder` and the non-exhaustive `status` set
5. **Resource Cleanup**: Properly close streams and connections on shutdown

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`.
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[GetOrderStatuses](https://www.dwellir.com/docs/hyperliquid/get_order_statuses)** - Point-in-time order status retrieval
- **[StreamRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/stream_raw_book_diffs)** - The sibling block-envelope stream for resting-book changes
- **[Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)** - Historical `node_order_statuses_by_block` downloads

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamOrderbookSnapshots - Real-time Order Book Streaming

# StreamOrderbookSnapshots - Real-time Order Book Streaming

Stream continuous order book snapshots starting from a position, providing real-time access to every individual open order across all markets on Hyperliquid. Each snapshot contains complete order metadata including order IDs, timestamps, trigger conditions, and child orders.

This RPC is the public method for streaming generated order-book snapshots. Snapshots intentionally do not appear in `ListFeeds`. Snapshot availability and maximum response size vary by endpoint. Oversized responses return `RESOURCE_EXHAUSTED`.

Large snapshots can exceed a gRPC client inbound message limit even when the endpoint can deliver the response. Client receive limits are separate from endpoint delivery limits. Configure them per client and workload; there is no universal fixed size that fits every snapshot.

Start this stream from a timestamp cursor. V3 `position.block_number` and V2 `block_height` are not supported for order-book snapshots.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`StreamOrderbookSnapshots` is essential for:

- **Market Making** - Monitor individual order changes and adjust quotes in real-time
- **Trading Algorithms** - Access live order-level data for execution strategies
- **Order Flow Analysis** - Track individual orders appearing and disappearing across snapshots
- **Whale Watching** - Detect large orders and trigger order clustering in real-time
- **Risk Management** - Monitor market conditions with full order granularity

Method signature

```protobuf
rpc StreamOrderbookSnapshots(StreamRequest) returns (stream Record) {}
```

V3 accepts only an inclusive Unix-millisecond `position.timestamp`; `position.block_number` and filters return `INVALID_ARGUMENT`, and explicit zero is invalid. A positioned stream starts with the snapshot covering the requested timestamp. An unpositioned stream sends the latest existing snapshot immediately and then each newer snapshot.

```protobuf
position: {
  timestamp: 1785736814057
}
```

In each `Record`, `block_number` and `timestamp` are typed transport cursors. They are outside the snapshot JSON. Decoded `Record.data` is the snapshot's top-level array of `[coin, [bids, asks]]` tuples. Snapshot RPCs are outside `ListFeeds`, and a timestamp outside retained history returns `NOT_FOUND`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. The first record is the snapshot covering this timestamp. Omit it to receive the latest snapshot first.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"timestamp":"1785736814057"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamOrderbookSnapshots
```

### Response Fields

- `block_number` (`optional int64, optional`): Typed transport cursor for the sequential Hyperliquid block number; it is outside decoded Record.data and is never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Typed transport cursor for the snapshot block time in Unix milliseconds; it is outside decoded Record.data.
- `data` (`bytes, required`): Record.data decodes directly to the top-level [coin, [bids, asks]] array.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "[[\"BTC\",[[{\"coin\":\"BTC\",\"side\":\"B\",\"limitPx\":\"114250.0\",\"sz\":\"0.25\",\"oid\":123456789,\"timestamp\":1785736813000,\"triggerCondition\":\"N/A\",\"isTrigger\":false,\"triggerPx\":\"0.0\",\"children\":[],\"isPositionTpsl\":false,\"reduceOnly\":false,\"orderType\":\"Limit\",\"origSz\":\"0.25\",\"tif\":\"Gtc\",\"cloid\":null}],[]]]]"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: The timestamp cursor is zero, a block-number cursor or filter was supplied, or the request is otherwise malformed.

#### Not found

- Code: `NOT_FOUND`
- Description: Snapshot availability varies by endpoint, and the requested timestamp is outside retained history.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: The snapshot stream is not currently available on this endpoint.

#### Snapshot exceeds a delivery limit

- Code: `RESOURCE_EXHAUSTED`
- Description: Snapshot availability and maximum response size vary by endpoint. Oversized responses return RESOURCE_EXHAUSTED.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"timestamp_ms":"1785736814057"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamOrderbookSnapshots
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 OrderBookSnapshot wrapper.

### Successful Response

```protobuf
message OrderBookSnapshot {
  bytes data = 1;
}
```

```protobuf
rpc StreamOrderbookSnapshots(Position) returns (stream OrderBookSnapshot) {}
```

V2 uses the inclusive `timestamp_ms` cursor; `block_height` is not supported for snapshots. An empty `Position` opens from the latest available snapshot.

### V2 decoded wrapper

V2 `OrderBookSnapshot.data` decodes to a JSON wrapper that keeps transport metadata around the snapshot array:

```json
{
  "block": "1058646974",
  "timestamp": 1785736814057,
  "data": [
    ["BTC", [[], []]]
  ]
}
```

## Response Stream

Each streamed message contains a full order book snapshot with every individual open order across all markets. Snapshot size varies with market conditions and endpoint. In V3, `block_number` and `timestamp` are typed transport cursors and decoded `Record.data` is the top-level array below. In V2, decode the wrapper above first and then read its inner `data` array.

Snapshot availability and maximum response size vary by endpoint. Oversized responses return `RESOURCE_EXHAUSTED`. Independently, configure the client inbound message limit per client and workload.

### Top-Level Structure

```json
[
  ["BTC", [[{ "coin": "BTC", "side": "B", "oid": 333003526755 }], []]],
  ["ETH", [[], []]]
]
```

The root array contains one entry per market. Transport cursors are not nested inside it.

### Market Entry Structure

Each element in decoded V3 `Record.data` is a 2-element array (tuple):

```json
[
  "BTC",
  [
    [ ...bid orders... ],
    [ ...ask orders... ]
  ]
]
```

| Index | Type      | Description                                                                                                                                                                                          |
| ----- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `[0]` | string    | Coin/asset symbol. Perp markets use ticker names (e.g. `"BTC"`, `"ETH"`). Spot markets use `@`-prefixed numeric IDs (e.g. `"@1"`, `"@105"`). Pre-market stocks use `xyz:` prefix (e.g. `"xyz:TSLA"`) |
| `[1]` | array\[2] | Two sub-arrays: `[0]` = bid orders (sorted descending by price), `[1]` = ask orders (sorted ascending by price)                                                                                      |

### Order Object

Each order in the bid/ask arrays is an individual order with full metadata. See the [GetOrderBookSnapshot Field Reference](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot#field-reference) for the complete field-by-field breakdown.

```json
{
  "coin": "BTC",
  "side": "B",
  "limitPx": "84500.0",
  "sz": "0.5",
  "oid": 333003526755,
  "timestamp": 1772276628506,
  "triggerCondition": "N/A",
  "isTrigger": false,
  "triggerPx": "0.0",
  "children": [],
  "isPositionTpsl": false,
  "reduceOnly": false,
  "orderType": "Limit",
  "origSz": "0.5",
  "tif": "Alo",
  "cloid": "0x00000000000000000000000000000318"
}
```

### Coin Symbol Conventions

| Pattern         | Type              | Examples                                    |
| --------------- | ----------------- | ------------------------------------------- |
| Plain ticker    | Perpetual futures | `"BTC"`, `"ETH"`, `"AAVE"`, `"ARB"`         |
| `@` + number    | Spot markets      | `"@1"`, `"@10"`, `"@105"`                   |
| `xyz:` + ticker | Pre-market stocks | `"xyz:TSLA"`, `"xyz:TSM"`, `"xyz:SOFTBANK"` |

## Common Use Cases

### 1. Order Flow Tracking

Compare consecutive snapshots to detect new, modified, and cancelled orders:

```python
class OrderFlowTracker:
    def __init__(self):
        self.previous_orders = {}  # oid -> order

    def track(self, snapshot):
        """Compare snapshots to detect order changes"""
        current_orders = {}

        for market in snapshot:
            coin = market[0]
            bids = market[1][0]
            asks = market[1][1]

            for order in bids + asks:
                current_orders[order['oid']] = order

        # Detect changes
        new_oids = set(current_orders) - set(self.previous_orders)
        removed_oids = set(self.previous_orders) - set(current_orders)

        for oid in new_oids:
            order = current_orders[oid]
            print(f'NEW: {order["coin"]} {order["side"]} '
                  f'{order["sz"]} @ {order["limitPx"]} '
                  f'({order["orderType"]})')

        for oid in removed_oids:
            order = self.previous_orders[oid]
            print(f'REMOVED: {order["coin"]} {order["side"]} '
                  f'{order["sz"]} @ {order["limitPx"]}')

        self.previous_orders = current_orders
```

### 2. Trigger Order Monitor

Track stop-loss and take-profit orders clustering around price levels:

```javascript
function analyzeTriggerOrders(snapshot, targetCoin) {
    for (const market of snapshot) {
        if (market[0] !== targetCoin) continue;

        const allOrders = [...market[1][0], ...market[1][1]];
        const triggerOrders = allOrders.filter(o => o.isTrigger);

        // Group by trigger price
        const triggerLevels = {};
        for (const order of triggerOrders) {
            const px = order.triggerPx;
            if (!triggerLevels[px]) {
                triggerLevels[px] = { count: 0, totalSz: 0, types: [] };
            }
            triggerLevels[px].count++;
            triggerLevels[px].totalSz += parseFloat(order.sz);
            triggerLevels[px].types.push(order.orderType);
        }

        // Report significant trigger clusters
        const sorted = Object.entries(triggerLevels)
            .sort((a, b) => b[1].totalSz - a[1].totalSz);

        console.log(`\n${targetCoin} Trigger Order Clusters:`);
        for (const [px, data] of sorted.slice(0, 5)) {
            console.log(`  ${px}: ${data.count} orders, ` +
                `size ${data.totalSz.toFixed(2)}`);
        }
    }
}
```

### 3. Large Order Detection

Monitor for whale-sized orders appearing in the stream:

```go
func detectLargeOrders(data []byte, threshold float64) {
    var snapshot [][]interface{}

    if err := json.Unmarshal(data, &snapshot); err != nil {
        return
    }

    for _, market := range snapshot {
        coin := market[0].(string)
        sides := market[1].([]interface{})

        for _, side := range sides {
            orders := side.([]interface{})
            for _, o := range orders {
                order := o.(map[string]interface{})
                sz, _ := strconv.ParseFloat(order["sz"].(string), 64)
                if sz >= threshold {
                    log.Printf("LARGE ORDER: %s %s %.2f @ %s (%s)",
                        coin, order["side"], sz,
                        order["limitPx"], order["orderType"])
                }
            }
        }
    }
}
```

## Error Handling and Reconnection

```javascript
class RobustOrderbookStreamer {
    constructor(endpoint, apiKey) {
        this.endpoint = endpoint;
        this.apiKey = apiKey;
        this.maxRetries = 5;
        this.retryDelay = 1000;
        this.currentRetries = 0;
    }

    async startStreamWithRetry() {
        while (this.currentRetries < this.maxRetries) {
            try {
                await this.startStream();
                this.currentRetries = 0;
                this.retryDelay = 1000;
            } catch (error) {
                this.currentRetries++;
                console.error(`Stream attempt ${this.currentRetries} failed:`, error.message);

                if (this.currentRetries >= this.maxRetries) {
                    throw new Error('Max retry attempts exceeded');
                }

                // Exponential backoff
                await this.sleep(this.retryDelay);
                this.retryDelay *= 2;
            }
        }
    }

    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
```

## Important Notes

- **Individual orders, not aggregated levels.** Each entry is an individual order with full metadata (order ID, timestamp, trigger info, children, etc.).
- **Bids are sorted by price descending** (highest price first). **Asks are sorted by price ascending** (lowest price first).
- **Children are never nested.** Child orders always have an empty `children` array.
- **Trigger orders** (`isTrigger: true`) have `tif: null` and meaningful `triggerCondition` / `triggerPx` values.
- **Once triggered**, the order becomes `isTrigger: false`, `triggerCondition: "Triggered"`, `triggerPx: "0.0"`, and receives a `tif` value (typically `"Gtc"`).

For detailed response examples including orders with TP/SL children, triggered orders, and all field descriptions, see the [GetOrderBookSnapshot documentation](https://www.dwellir.com/docs/hyperliquid/get_order_book_snapshot#response-examples).

## Best Practices

1. **Message Size Configuration**: Configure the client inbound message limit per client and workload, and account separately for endpoint delivery limits; oversized responses return `RESOURCE_EXHAUSTED`.
2. **Connection Management**: Implement robust reconnection logic with exponential backoff
3. **Memory Management**: Use bounded collections for storing historical snapshots; avoid keeping many full snapshots in memory simultaneously
4. **Performance**: Process snapshots asynchronously to avoid blocking the stream
5. **Monitoring**: Track stream health and snapshot rates
6. **Resource Cleanup**: Properly close streams and connections on shutdown

## Current Limitations

- **Replay History**: Available snapshot history varies by endpoint; a timestamp outside retained history returns `NOT_FOUND`
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems
- **Availability**: Snapshot availability and maximum response size vary by endpoint; oversized responses return `RESOURCE_EXHAUSTED`

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[Copy Trading Bot](https://github.com/dwellir-public/gRPC-code-examples/tree/main/copy-trading-bot)** - Production-ready trading bot example
- **[Pricing](https://www.dwellir.com/docs/hyperliquid/pricing)** - Dedicated node cluster pricing details

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamRawBookDiffs - Real-time Book Diff Streaming

# StreamRawBookDiffs - Real-time Book Diff Streaming

Stream incremental order book changes starting from a position, providing real-time access to every addition, size change, and removal in Hyperliquid's resting book.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`StreamRawBookDiffs` is essential for:

- **Order Book Reconstruction** - Maintain a live local book by applying per-block diffs
- **Liquidity Analysis** - Track depth, spread, and resting-order churn over time
- **Microstructure Research** - Study how the book evolves block by block
- **Backtesting Inputs** - Replay historical book changes from a chosen position

Method signature

```protobuf
rpc StreamRawBookDiffs(StreamRequest) returns (stream Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`. Explicit zero is invalid. A positioned call replays inclusively and then tails live; an empty request tails newly written diffs. Set `progress` to opt in to [progress frames](#progress-frames).

```protobuf
position: {
  block_number: 1058646974
}
filter: {
  fields: {
    field: "coins"
    op: FILTER_OP_IN
    values: "BTC"
    values: "ETH"
  }
}
```

Raw book diffs accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. Records with zero matching events are skipped. Each `Record` contains optional `block_number` and `timestamp` cursors plus the filtered envelope in `data`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

Raw diffs are not an initial book state. Seed reconstruction from a snapshot or another known state, then apply ordered diffs.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to tail newly written records.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.
- `progress.interval_ms` (`uint32, optional`): Set progress to opt in to progress frames; leave it unset for none. Longest silence in milliseconds before a progress frame. 0 selects the feed default, currently 20000 within bounds of 10000 to 60000; ListFeeds reports the bounds in FeedInfo.progress.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamRawBookDiffs
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_raw_book_diffs_by_block, with non-matching events removed when a filter is applied.
- `progress` (`StreamProgress, optional`): Set only on progress frames, which leave data, block_number, and timestamp unset. Check it before decoding data.
- `progress.scanned_through.block_number` (`int64, optional`): Inclusive cursor of the newest block the stream examined, sent or removed by the filter. A valid resume position; unset until the stream has examined a record.
- `progress.timestamp` (`optional int64, optional`): Source time at scanned_through in Unix milliseconds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Invalid progress request

- Code: `INVALID_ARGUMENT`
- Description: A nonzero progress.interval_ms is outside the bounds advertised in FeedInfo.progress.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Replay capacity is temporarily unavailable; retry with backoff.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Progress frames do not reset the timeout. Reconnect from the last cursor received.

#### Records lost

- Code: `DATA_LOSS`
- Description: The stream lost records, for example because it fell behind the live feed. It ends before sending any cursor past them; reconnect from the last cursor received to re-read the gap.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamRawBookDiffs
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockRawBookDiffs wrapper.

### Successful Response

```protobuf
message BlockRawBookDiffs {
  bytes data = 1;
}
```

```protobuf
rpc StreamRawBookDiffs(Position) returns (stream BlockRawBookDiffs) {}
```

V2 accepts the inclusive cursor fields `block_height` and `timestamp_ms`; an empty `Position` tails new diffs. It returns the source JSON in `BlockRawBookDiffs.data`.

## Response Stream

V3 carries the JSON-encoded `node_raw_book_diffs_by_block` envelope in `Record.data`.

V2 carries the JSON-encoded `node_raw_book_diffs_by_block` envelope in `BlockRawBookDiffs.data`.

Decode the `data` field to access:

- Block reference (`local_time`, `block_time`, `block_number`)
- An `events` array of incremental resting-book changes
- Per-change order context (owner, order ID, coin, side, price)

## Full Book Diff Spec

`StreamRawBookDiffs` emits a JSON payload matching Hyperliquid's `node_raw_book_diffs_by_block` format. Below is the exact structure.

Top-level keys (always present):

```json
{
  "local_time": "2026-04-20T00:00:00.040479928",   // ISO-8601 timestamp when node processed the block (nanosecond precision)
  "block_time": "2026-04-19T23:59:59.576040791",    // ISO-8601 timestamp from block consensus
  "block_number": 12345,                            // Block height containing these changes
  "events": [                                       // Array of incremental book-change objects
    {
      "user": "0x1234567890abcdef1234567890abcdef12345678",  // Order owner address
      "oid": 12345,                                 // Order identifier
      "coin": "BTC",                                // Coin identifier
      "side": "B",                                  // "B" (buy) or "A" (sell/ask)
      "px": "42000.0",                              // Price (numeric string)
      "raw_book_diff": "remove"                     // Change applied to the book (see shapes below)
    },
    {
      "user": "0x1234567890abcdef1234567890abcdef12345678",
      "oid": 12346,
      "coin": "BTC",
      "side": "A",
      "px": "42050.0",
      "raw_book_diff": { "new": { "sz": "0.5" } }   // Order added with size
    },
    {
      "user": "0x1234567890abcdef1234567890abcdef12345678",
      "oid": 12347,
      "coin": "BTC",
      "side": "A",
      "px": "42100.0",
      "raw_book_diff": { "update": { "newSz": "0.4", "origSz": "1.0" } }  // Resting size changed
    }
  ]
}
```

Book diff event fields (`events[i]`):

| Field           | Type             | Description                                                                                     |
| --------------- | ---------------- | ----------------------------------------------------------------------------------------------- |
| `user`          | string           | Order owner address                                                                             |
| `oid`           | number           | Order identifier. Not reliably unique across coins. See [Order Identifiers](#order-identifiers) |
| `coin`          | string           | Coin identifier (e.g. `"BTC"`, `"ETH"`)                                                         |
| `side`          | string           | `"B"` for buy, `"A"` for sell                                                                   |
| `px`            | string           | Price (numeric string)                                                                          |
| `raw_book_diff` | string or object | The change applied to the book. One of three shapes (below)                                     |

The `raw_book_diff` value takes one of three shapes:

| Shape                                                 | Meaning                                       |
| ----------------------------------------------------- | --------------------------------------------- |
| `"remove"` (string literal)                           | Order removed from the book                   |
| `{ "new": { "sz": string } }`                         | Order added with the given size               |
| `{ "update": { "newSz": string, "origSz": string } }` | Resting size changed from `origSz` to `newSz` |

Guarantees and alignment:

- `events` contains all book changes from the block, across all coins and users.
- Messages arrive in strictly increasing `block_number`, one per source block (including blocks with an empty `events` array).
- `block_number` is sequential and distinct from the potentially skipping `abci_block.round` consensus value in StreamBlocks; `block_time` aligns with `abci_block.time`.

Developer tips:

- Apply diffs in order: branch on the `raw_book_diff` shape to add, resize, or remove the resting order.
- Key your local book on `(coin, oid)`, never on `oid` alone. See [Order Identifiers](#order-identifiers).
- Normalize `px`, `sz`, `newSz`, and `origSz` (strings) to numeric types as appropriate.

## Order Identifiers

`oid` is **not reliably unique across coins**. Consumers that index or join per-order state must key on the `(coin, oid)` tuple, never on `oid` alone.

Outcome markets (HIP-4) demonstrably reuse oids across the two sides of a single market (for example `#30` and `#31`) within one block, so a diff for an `oid` on one coin is not necessarily the same logical order as a diff for that `oid` on another coin in the same block. Keying on `(coin, oid)` is safe whether or not oids turn out to be globally unique elsewhere.

## Common Use Cases

### 1. Local Book Reconstruction

```python
class BookReconstructor:
    def __init__(self):
        # (coin, oid) -> {"side", "px", "sz"}
        self.orders = {}

    def apply_block(self, block):
        for event in block.get('events', []):
            key = (event['coin'], event['oid'])
            diff = event['raw_book_diff']

            if diff == 'remove':
                self.orders.pop(key, None)
            elif 'new' in diff:
                self.orders[key] = {
                    'side': event['side'],
                    'px': event['px'],
                    'sz': diff['new']['sz'],
                }
            elif 'update' in diff:
                order = self.orders.get(key)
                if order:
                    order['sz'] = diff['update']['newSz']
```

### 2. Streaming Diffs in Python

Open V3 with an empty `StreamRequest` to tail newly written records, or set `StreamRequest.position.block_number` for inclusive replay. Decode each `Record.data` envelope before applying the diffs with the reconstructor above.

```python
import grpc
import json
import os
import hyperliquid_pb2
import hyperliquid_pb2_grpc

def stream_book_diffs():
    endpoint = os.getenv('HYPERLIQUID_ENDPOINT')
    api_key = os.getenv('API_KEY')

    credentials = grpc.ssl_channel_credentials()
    options = [('grpc.max_receive_message_length', 150 * 1024 * 1024)]  # 150MB max
    metadata = [('x-api-key', api_key)]

    with grpc.secure_channel(endpoint, credentials, options=options) as channel:
        client = hyperliquid_pb2_grpc.HyperliquidL1GatewayStub(channel)

        # Empty Position means latest; set block_height or timestamp_ms to backfill
        request = hyperliquid_pb2.Position()

        for response in client.StreamRawBookDiffs(request, metadata=metadata):
            block = json.loads(response.data)
            print(f"block {block['block_number']}: {len(block.get('events', []))} diffs")
```

## Progress Frames

Progress frames are an application-level heartbeat. Set `StreamRequest.progress` to receive one after each interval of silence. A `users` or `coins` filter can leave the stream silent for minutes. They keep it open through idle-limited proxies, which HTTP/2 keepalive pings do not, and advance your resume cursor through blocks the filter removed.

A progress frame sets `Record.progress.scanned_through.block_number` and leaves the data fields unset, so check `progress` before decoding `data`. Persist `scanned_through` as an inclusive resume cursor. See [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) for the full contract.

V2 streams do not send progress frames. Use the V3 method to opt in.

## Error Handling and Reconnection

Reconnect with `StreamRequest.position.block_number` set to the last committed V3 cursor, from a data record or a progress frame's `scanned_through`. Replay is inclusive, so deduplicate that record before applying subsequent diffs.

Reconnect by replaying from the last processed block. Pass the next `block_height` in the `Position` so no diffs are skipped or double-applied.

```python
def stream_with_resume(client, metadata, start_block):
    next_block = start_block
    while True:
        request = hyperliquid_pb2.Position(block_height=next_block)
        try:
            for response in client.StreamRawBookDiffs(request, metadata=metadata):
                block = json.loads(response.data)
                process(block)
                next_block = block['block_number'] + 1
        except grpc.RpcError as e:
            print(f"stream error, resuming from {next_block}: {e}")
```

## Best Practices

1. **Connection Management**: Implement robust reconnection logic with exponential backoff
2. **Resumable State**: Follow the version-specific recovery guidance above and persist the cursor required by your selected API version
3. **Stable Keys**: Index resting orders on `(coin, oid)` to stay correct across coins
4. **Performance**: Apply diffs asynchronously to avoid blocking the stream
5. **Resource Cleanup**: Properly close streams and connections on shutdown

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`.
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[GetRawBookDiffs](https://www.dwellir.com/docs/hyperliquid/get_raw_book_diffs)** - Point-in-time book diff retrieval
- **[StreamOrderStatuses](https://www.dwellir.com/docs/hyperliquid/stream_order_statuses)** - The sibling block-envelope stream for order lifecycle events
- **[Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)** - Historical `node_raw_book_diffs_by_block` downloads

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamTpslUpdates - Stream TP/SL Order Updates

# StreamTpslUpdates - Stream TP/SL Order Updates

`StreamTpslUpdates` exposes the lifecycle of open take-profit and stop-loss trigger orders, including position-level TP/SL effective sizes.

## Request and opening behavior

An empty `coins` list means all perp coins, including enabled HIP-3 perps. Explicit coins are deduplicated and validated against the perp universe; blank and wildcard entries are invalid. Optional `users` filters owners case-insensitively.

The first frame has `snapshot: true`, `sequence: 1`, and matching `ADD` diffs. Later `ADD`, `REMOVE`, and `UPDATE` diffs preserve the same sequence even when filtering leaves `diffs` empty. `resolved_sz` is unset only until a position-level TP/SL size can first be resolved.

## Request Parameters

- `coins` (`repeated string, optional`): Optional exact perp-coin scope; empty means all perps, while blank and wildcard entries are invalid.
- `users` (`repeated string, optional`): Optional 0x-prefixed owner addresses matched case-insensitively.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamTpslUpdates(ctx, &pb.TpslUpdatesRequest{
        Coins: []string{"BTC", "ETH"},
        Users: []string{"0x1111111111111111111111111111111111111111"},
    })
    if err != nil {
        log.Fatal(err)
    }
    var last uint64
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d snapshot=%t sequence=%d diffs=%d", update.GetBlockNumber(), update.GetSnapshot(), update.GetSequence(), len(update.GetDiffs()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Frame block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `diffs` (`repeated TpslOrderDiff, required`): Trigger-order lifecycle changes, or matching ADD entries on the snapshot.
- `diffs.diff_type` (`TpslDiffType, required`): ADD, REMOVE, or UPDATE operation.
- `diffs.oid` (`uint64, required`): Trigger-order identifier.
- `diffs.coin` (`string, required`): Perp coin identifier.
- `diffs.user` (`string, required`): Order owner address.
- `diffs.side` (`string, required`): Native side B or A.
- `diffs.trigger_px` (`string, required`): Trigger price as a decimal string.
- `diffs.limit_px` (`string, required`): Limit price as a decimal string.
- `diffs.sz` (`string, required`): Configured order size as a decimal string.
- `diffs.trigger_condition` (`string, required`): Native trigger condition.
- `diffs.order_type` (`string, required`): Native trigger-order type.
- `diffs.is_position_tpsl` (`bool, required`): Whether the trigger is position-level TP/SL.
- `diffs.reduce_only` (`bool, required`): Whether the trigger order is reduce-only.
- `diffs.timestamp` (`int64, required`): Order placement time in Unix milliseconds.
- `diffs.reason` (`optional string, optional`): Native removal reason, set on REMOVE.
- `diffs.resolved_sz` (`optional string, optional`): Live effective size; unset until a position-level trigger can first be resolved.
- `snapshot` (`bool, required`): True on the opening rebuild frame.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the snapshot.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
diffs: {
  diff_type: TPSL_DIFF_TYPE_ADD
  oid: 123456789
  coin: "BTC"
  user: "0x1111111111111111111111111111111111111111"
  side: "A"
  trigger_px: "110000.0"
  limit_px: "109900.0"
  sz: "0.0"
  trigger_condition: "Price below 110000"
  order_type: "Stop Market"
  is_position_tpsl: true
  reduce_only: true
  timestamp: 1785736813000
  resolved_sz: "0.25"
}
snapshot: true
sequence: 1
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: A coin or user is malformed, or an explicitly listed perp is unavailable.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: The requested TP/SL view is not ready.

### Lost incremental frames

- Code: `ABORTED`
- Description: Frame loss or a stream state reset requires reconnecting and rebuilding from a new snapshot.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require contiguous `sequence` values. Frame loss or a stream state reset returns `ABORTED`; reconnect and rebuild from the new snapshot. Quiet blocks produce no frame, and an idle open stream remains healthy. See the [shared market-stream contract](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) for common errors.

Related references: [StreamL4OrderUpdates](https://www.dwellir.com/docs/hyperliquid/stream_l4_order_updates) and [StreamTwapStatuses](https://www.dwellir.com/docs/hyperliquid/stream_twap_statuses).

---

## StreamTrades - Stream Normalized Trades

# StreamTrades - Stream Normalized Trades

`StreamTrades` sends normalized executions in one batch per `(block, coin)`. Within one block, identify a match by `(coin, tid)`. Across blocks, include the batch's `block_number` in the match key.

A trade can contain multiple makers. Preserve every address in `bid_users` and `ask_users`.

## Request and live-only behavior

`coins` is required and accepts `1` through `20` distinct, validated identifiers. Optional `users` keeps a trade when any counterparty matches case-insensitively. The coin and user filters combine using AND semantics.

The stream starts with executions observed after subscription. It has no opening snapshot or historical backfill. Per-coin order is preserved; ordering between coins is unspecified. A batch emptied by the user filter is dropped.

## Request Parameters

- `coins` (`repeated string, required`): One to 20 distinct, validated native coin identifiers; duplicates are ignored before applying the cap.
- `users` (`repeated string, optional`): Optional counterparties; a trade matches when any bid-side or ask-side address matches case-insensitively.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamTrades(ctx, &pb.TradesRequest{
        Coins: []string{"BTC", "ETH"},
        Users: []string{"0x1111111111111111111111111111111111111111"},
    })
    if err != nil {
        log.Fatal(err)
    }
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        for _, trade := range update.GetTrades() {
            log.Printf("block=%d coin=%s tid=%d side=%s px=%s sz=%s bid_users=%v ask_users=%v", update.GetBlockNumber(), trade.GetCoin(), trade.GetTid(), trade.GetSide(), trade.GetPx(), trade.GetSz(), trade.GetBidUsers(), trade.GetAskUsers())
        }
    }
}
```

## Response Fields

- `time` (`int64, required`): Batch block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `trades` (`repeated Trade, required`): Normalized trades for one coin in this block.
- `trades.coin` (`string, required`): Native coin identifier.
- `trades.side` (`string, required`): Taker side B or A.
- `trades.px` (`string, required`): Execution price as a decimal string.
- `trades.sz` (`string, required`): Executed size as a decimal string.
- `trades.hash` (`string, required`): Transaction hash.
- `trades.time` (`int64, required`): Execution time in Unix milliseconds.
- `trades.tid` (`uint64, required`): Within one block, use (coin, tid). Across blocks, include the batch's block_number.
- `trades.bid_users` (`repeated string, required`): Every bid-side counterparty; a multi-maker match can contain several addresses.
- `trades.ask_users` (`repeated string, required`): Every ask-side counterparty; a multi-maker match can contain several addresses.
- `trades.synthetic` (`bool, required`): True only for a synthesized HIP-4 sibling trade.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
trades: {
  coin: "BTC"
  side: "B"
  px: "114250.0"
  sz: "0.75"
  hash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  time: 1785736814057
  tid: 99887766
  bid_users: "0x1111111111111111111111111111111111111111"
  ask_users: "0x2222222222222222222222222222222222222222"
  ask_users: "0x3333333333333333333333333333333333333333"
  synthetic: false
}
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: The coin list or a user address is malformed, or an explicitly listed coin is unavailable.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: Live trades are not currently available.

### Lost live trades

- Code: `ABORTED`
- Description: Frame loss or a stream state reset ended this live-only stream.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Delivery and recovery

Trades do not carry a sequence. Frame loss or a stream state reset closes the stream with `ABORTED`; reconnecting resumes live delivery but does not recover missed executions. Use the [raw fills stream](https://www.dwellir.com/docs/hyperliquid/stream_fills), [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data), or an indexed product when durable recovery is required. Shared errors are documented on the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service).

Related reference: [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills).

---

## StreamTwapStatuses - Real-time TWAP Status Streaming

# StreamTwapStatuses - Real-time TWAP Status Streaming

Stream TWAP order lifecycle events starting from a position, providing real-time access to TWAP state updates across Hyperliquid.

Clone our [gRPC Code Examples Repository](https://github.com/dwellir-public/gRPC-code-examples) for complete, runnable implementations in Go, Python, and Node.js.

## When to Use This Method

`StreamTwapStatuses` is essential for:

- **TWAP Lifecycle Tracking** - Follow TWAP orders as their state changes
- **Execution Monitoring** - Track executed size and notional over time
- **Strategy Analytics** - Reconstruct TWAP execution progress across blocks
- **Compliance and Auditing** - Record TWAP status transitions with block alignment

`StreamTwapStatuses` reports lifecycle changes after the order exists on HyperCore. To decode the signed request that created or canceled a TWAP, pair this stream with [twapOrder](https://www.dwellir.com/docs/hyperliquid/twapOrder) and [twapCancel](https://www.dwellir.com/docs/hyperliquid/twapCancel) actions from [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks).

Method signature

```protobuf
rpc StreamTwapStatuses(StreamRequest) returns (stream Record) {}
```

V3 accepts an inclusive `position.block_number` or Unix-millisecond `position.timestamp`. Explicit zero is invalid. A positioned call replays inclusively and then tails live; an empty request tails newly written TWAP status records. Set `progress` to opt in to [progress frames](#progress-frames).

```protobuf
filter: {
  fields: {
    field: "coins"
    op: FILTER_OP_IN
    values: "BTC"
  }
}
```

TWAP statuses accept `users` and `coins` filters. User matching is case-insensitive and coin matching is case-sensitive; values within a field use OR semantics and separate fields use AND semantics. Records with zero matching events are skipped. Each `Record` contains optional `block_number` and `timestamp` cursors plus the filtered envelope in `data`. A pruned position returns `NOT_FOUND`; malformed filters return `INVALID_ARGUMENT`.

## V3 reference

### Request Parameters

- `position.timestamp` (`int64, optional`): Inclusive V3 Unix-millisecond cursor. Omit the position to tail newly written records.
- `position.block_number` (`int64, optional`): Inclusive V3 sequential block cursor. Explicit zero is invalid.
- `filter.fields` (`FieldFilter[], optional`): V3 users/coins constraints. Fields AND together; values within one field OR together.
- `filter.fields.field` (`string, required`): Feed-advertised filter field name, either users or coins.
- `filter.fields.op` (`FilterOp, optional`): FILTER_OP_UNSPECIFIED or FILTER_OP_IN.
- `filter.fields.values` (`string[], required`): One or more accepted values; entries within the list use OR semantics.
- `progress.interval_ms` (`uint32, optional`): Set progress to opt in to progress frames; leave it unset for none. Longest silence in milliseconds before a progress frame. 0 selects the feed default, currently 20000 within bounds of 10000 to 60000; ListFeeds reports the bounds in FeedInfo.progress.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamTwapStatuses
```

### Response Fields

- `block_number` (`optional int64, optional`): Sequential Hyperliquid block cursor; never the HyperBFT consensus round.
- `timestamp` (`optional int64, optional`): Record time in Unix milliseconds.
- `data` (`bytes, required`): Bytes from the node_twap_statuses_by_block, with non-matching events removed when a filter is applied.
- `progress` (`StreamProgress, optional`): Set only on progress frames, which leave data, block_number, and timestamp unset. Check it before decoding data.
- `progress.scanned_through.block_number` (`int64, optional`): Inclusive cursor of the newest block the stream examined, sent or removed by the filter. A valid resume position; unset until the stream has examined a record.
- `progress.timestamp` (`optional int64, optional`): Source time at scanned_through in Unix milliseconds.

### Successful Response

```protobuf
block_number: 1058646974
timestamp: 1785736814057
data: "{\"block_number\":1058646974,\"events\":[]}"
```

### Error Responses

#### Invalid argument

- Code: `INVALID_ARGUMENT`
- Description: A cursor is zero or malformed, or a filter has an unsupported field, duplicate field, empty name, or empty value list.

#### Invalid progress request

- Code: `INVALID_ARGUMENT`
- Description: A nonzero progress.interval_ms is outside the bounds advertised in FeedInfo.progress.

#### Not found

- Code: `NOT_FOUND`
- Description: Available replay history varies by feed and endpoint. A cursor outside retained history returns NOT_FOUND.

#### Replay capacity exhausted

- Code: `RESOURCE_EXHAUSTED`
- Description: Replay capacity is temporarily unavailable; retry with backoff.

#### Filter operator not implemented

- Code: `UNIMPLEMENTED`
- Description: The requested filter operator is well formed but is not implemented by this gateway version.

#### Stream unavailable

- Code: `UNAVAILABLE`
- Description: No new records arrived before the stream timeout, or the stream failed mid-stream. Progress frames do not reset the timeout. Reconnect from the last cursor received.

#### Records lost

- Code: `DATA_LOSS`
- Description: The stream lost records, for example because it fell behind the live feed. It ends before sending any cursor past them; reconnect from the last cursor received to re-read the gap.

#### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The stream could not deliver records in time because the client read too slowly or stopped reading; reconnect from the last processed cursor.

#### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: The request did not include usable authentication metadata.

#### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential is not permitted to call this service.

## V2 reference

### Request Parameters

- `timestamp_ms` (`int64, optional`): Inclusive Unix-millisecond cursor. Omit it to start from the latest data and continue streaming.
- `block_height` (`int64, optional`): Inclusive block-height cursor. Omit it to start from the latest data and continue streaming.

### Request Example

```bash
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v2.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"block_height":"1058646974"}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v2.HyperliquidL1Gateway/StreamTwapStatuses
```

### Response Fields

- `data` (`bytes, required`): JSON-encoded payload returned in the V2 BlockTwapStatuses wrapper.

### Successful Response

```protobuf
message BlockTwapStatuses {
  bytes data = 1;
}
```

```protobuf
rpc StreamTwapStatuses(Position) returns (stream BlockTwapStatuses) {}
```

V2 accepts the inclusive cursor fields `block_height` and `timestamp_ms`; an empty `Position` tails new TWAP status records. It returns the source JSON in `BlockTwapStatuses.data`.

## Response Stream

V3 carries the JSON-encoded `node_twap_statuses_by_block` envelope in `Record.data`.

V2 carries the JSON-encoded `node_twap_statuses_by_block` envelope in `BlockTwapStatuses.data`.

Decode the `data` field to access:

- Block reference (`local_time`, `block_time`, `block_number`)
- An `events` array of TWAP status records
- A TWAP state object behind each lifecycle update

## Per-Block Delivery

`StreamTwapStatuses` emits one message per source block-envelope record, including records with an empty `events` array. Most blocks do not contain a TWAP lifecycle update, so empty envelopes are normal. They still let consumers advance their cursor and confirm exactly which block was last processed.

V3 clients must detect discontinuities and duplicates and persist only cursors present on `Record`. Reconnect with `StreamRequest.position.block_number` or `position.timestamp`; replay is inclusive.

V2 clients reconnect with the next `block_height` or a `timestamp_ms` in `Position`. Both are inclusive; an empty or zero `Position` targets the latest data.

## Full TWAP Status Spec

`StreamTwapStatuses` emits a JSON payload matching Hyperliquid's `node_twap_statuses_by_block` format, passed through byte-for-byte from the node with no normalization. The envelope is the same block-envelope shape as fills, but `events` holds TWAP lifecycle objects rather than fill tuples.

Top-level keys (always present):

```json
{
  "local_time": "2026-07-03T06:00:14.508835456",
  "block_time": "2026-07-03T06:00:14.057132297",
  "block_number": 1058646974,
  "events": [
    {
      "time": "2026-07-03T06:00:14.057132297",
      "twap_id": 1999381,
      "state": {
        "coin": "kPEPE",
        "user": "0x2ee1f7d5650bb9bc08e101dc5ab2300b4f5c1be9",
        "side": "B",
        "sz": "555555.0",
        "executedSz": "555555.0",
        "executedNtl": "1371.51378",
        "minutes": 5,
        "reduceOnly": false,
        "randomize": false,
        "timestamp": 1783058112775
      },
      "status": "finished"
    }
  ]
}
```

Status event fields (`events[i]`):

| Field     | Type             | Description                                                                      |
| --------- | ---------------- | -------------------------------------------------------------------------------- |
| `time`    | string           | Event timestamp in the no-`Z` layout. A string, not an integer millisecond value |
| `twap_id` | number           | TWAP order identifier                                                            |
| `state`   | object           | TWAP state at the lifecycle update. See [TWAP State Object](#twap-state-object)  |
| `status`  | string or object | Lifecycle status. See [Status Values](#status-values)                            |

Every event is global, not user-scoped to the API key. Filter by `state.user`, `state.coin`, or `twap_id` in your application when you only need a subset.

### TWAP State Object

| Field         | Type    | Description                                      |
| ------------- | ------- | ------------------------------------------------ |
| `coin`        | string  | Coin identifier                                  |
| `user`        | string  | User address                                     |
| `side`        | string  | `"B"` for buy, `"A"` for sell                    |
| `sz`          | string  | Target TWAP size as a numeric string             |
| `executedSz`  | string  | Executed size so far as a numeric string         |
| `executedNtl` | string  | Executed notional so far as a numeric string     |
| `minutes`     | number  | TWAP duration in minutes                         |
| `reduceOnly`  | boolean | Whether the TWAP is reduce-only                  |
| `randomize`   | boolean | Whether the TWAP randomizes slice timing or size |
| `timestamp`   | number  | TWAP creation time in Unix milliseconds          |

The `state` object is a snapshot of the TWAP at the lifecycle event, not a fill-by-fill execution log. Use `executedSz` and `executedNtl` to measure aggregate progress for that TWAP at the event boundary. For individual trade executions, consume [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) and join on user, coin, and time windows according to your own strategy model.

### Status Values

Observed string `status` values include:

| Status       | Meaning                                                          |
| ------------ | ---------------------------------------------------------------- |
| `activated`  | TWAP order became active                                         |
| `finished`   | TWAP execution completed or otherwise reached its terminal state |
| `terminated` | TWAP order was terminated before normal completion               |

`status` can also be an object when the lifecycle update carries an error:

```json
{
  "status": {
    "error": "Reduce only order would increase position."
  }
}
```

Treat the `status` set as non-exhaustive. Hyperliquid can add new lifecycle states and error payloads over time.

### Lifecycle Examples

An `activated` event starts a TWAP lifecycle. At activation, `executedSz` and `executedNtl` are typically zero:

```json
{
  "time": "2026-07-03T06:00:30.373151284",
  "twap_id": 1999392,
  "state": {
    "coin": "xyz:NBIS",
    "user": "0x6f97b7de6be7b7771e975e46bae96c35e332e172",
    "side": "B",
    "sz": "226.72",
    "executedSz": "0.0",
    "executedNtl": "0.0",
    "minutes": 7,
    "reduceOnly": false,
    "randomize": false,
    "timestamp": 1783058430373
  },
  "status": "activated"
}
```

A `terminated` event records the final observed state when a TWAP stops before normal completion. Partial execution is visible through `executedSz` and `executedNtl`:

```json
{
  "time": "2026-07-03T06:02:08.835250901",
  "twap_id": 1999394,
  "state": {
    "coin": "xyz:NBIS",
    "user": "0x6f97b7de6be7b7771e975e46bae96c35e332e172",
    "side": "B",
    "sz": "226.7",
    "executedSz": "60.45",
    "executedNtl": "13377.625",
    "minutes": 7,
    "reduceOnly": false,
    "randomize": false,
    "timestamp": 1783058434767
  },
  "status": "terminated"
}
```

Guarantees and alignment:

- `events` contains TWAP status records from the block across all users.
- Messages arrive in strictly increasing `block_number`, one per source block-envelope record.
- `block_number` is sequential and distinct from the potentially skipping `abci_block.round` consensus value in StreamBlocks; `block_time` aligns with `abci_block.time`.

Developer tips:

- Use `twap_id` as the primary key for TWAP lifecycle state.
- Parse `sz`, `executedSz`, and `executedNtl` as decimals to avoid precision loss.
- Treat `time` as a formatted string, distinct from the integer-millisecond `timestamp` inside `state`.
- Handle empty `events` arrays; quiet blocks are normal.
- Store the raw block envelope if you need reproducible audits; the gateway does not normalize or reshape the node payload.

## Common Use Cases

### 1. TWAP Lifecycle Index

```python
from decimal import Decimal

def apply_twap_status(block, index):
    for event in block.get('events', []):
        state = event['state']
        target = Decimal(state['sz'])
        executed = Decimal(state['executedSz'])

        status = event['status']
        status_key = status if isinstance(status, str) else 'error'

        index[event['twap_id']] = {
            'status': status,
            'status_key': status_key,
            'user': state['user'],
            'coin': state['coin'],
            'side': state['side'],
            'target_size': target,
            'executed_size': executed,
            'progress': executed / target if target else Decimal('0'),
            'block_number': block['block_number'],
            'block_time': block['block_time'],
        }
```

### 2. TWAP Alert Stream

```python
def alert_on_terminal_twaps(block):
    for event in block.get('events', []):
        status = event['status']
        if status not in ('finished', 'terminated') and not isinstance(status, dict):
            continue

        state = event['state']
        status_label = status.get('error', 'error') if isinstance(status, dict) else status
        print(
            f"{status_label} twap={event['twap_id']} "
            f"user={state['user']} coin={state['coin']} "
            f"executed={state['executedSz']}/{state['sz']}"
        )
```

### 3. Streaming TWAP Statuses in Python

Open V3 with an empty `StreamRequest` to tail newly written records, or set `StreamRequest.position.block_number` for inclusive replay. Decode each `Record.data` envelope and apply it with the lifecycle-index helper above.

```python
import grpc
import json
import os
from decimal import Decimal
import hyperliquid_pb2
import hyperliquid_pb2_grpc

def apply_twap_status(block, index):
    for event in block.get('events', []):
        state = event['state']
        target = Decimal(state['sz'])
        executed = Decimal(state['executedSz'])

        status = event['status']
        status_key = status if isinstance(status, str) else 'error'

        index[event['twap_id']] = {
            'status': status,
            'status_key': status_key,
            'user': state['user'],
            'coin': state['coin'],
            'side': state['side'],
            'target_size': target,
            'executed_size': executed,
            'progress': executed / target if target else Decimal('0'),
            'block_number': block['block_number'],
        }

def stream_twap_statuses():
    endpoint = os.getenv('HYPERLIQUID_ENDPOINT')
    api_key = os.getenv('API_KEY')

    credentials = grpc.ssl_channel_credentials()
    options = [('grpc.max_receive_message_length', 150 * 1024 * 1024)]  # 150MB max
    metadata = [('x-api-key', api_key)]

    with grpc.secure_channel(endpoint, credentials, options=options) as channel:
        client = hyperliquid_pb2_grpc.HyperliquidL1GatewayStub(channel)

        # Empty Position means latest; set block_height or timestamp_ms to backfill
        request = hyperliquid_pb2.Position()

        twaps = {}

        for response in client.StreamTwapStatuses(request, metadata=metadata):
            block = json.loads(response.data)
            apply_twap_status(block, twaps)
```

## Progress Frames

Progress frames are an application-level heartbeat. Set `StreamRequest.progress` to receive one after each interval of silence. A `users` or `coins` filter can leave the stream silent for minutes. They keep it open through idle-limited proxies, which HTTP/2 keepalive pings do not, and advance your resume cursor through blocks the filter removed.

A progress frame sets `Record.progress.scanned_through.block_number` and leaves the data fields unset, so check `progress` before decoding `data`. Persist `scanned_through` as an inclusive resume cursor. See [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames) for the full contract.

V2 streams do not send progress frames. Use the V3 method to opt in.

## Error Handling and Reconnection

Reconnect with `StreamRequest.position.block_number` set to the last committed V3 cursor, from a data record or a progress frame's `scanned_through`. Replay is inclusive, so deduplicate that record before advancing.

Reconnect by replaying from the last processed block. Pass the next `block_height` in the `Position` so no events are skipped or duplicated.

```python
def stream_with_resume(client, metadata, start_block):
    next_block = start_block
    while True:
        request = hyperliquid_pb2.Position(block_height=next_block)
        try:
            for response in client.StreamTwapStatuses(request, metadata=metadata):
                block = json.loads(response.data)
                process(block)
                next_block = block['block_number'] + 1
        except grpc.RpcError as e:
            print(f"stream error, resuming from {next_block}: {e}")
```

## Best Practices

1. **Connection Management**: Implement robust reconnection logic with exponential backoff
2. **Resumable State**: Follow the version-specific recovery guidance above and persist the cursor required by your selected API version
3. **Stable Keys**: Index TWAP lifecycle state on `twap_id`
4. **Defensive Parsing**: Handle empty `events` arrays, unknown future string statuses, and object status payloads
5. **Numeric Precision**: Parse numeric strings with decimal-safe types
6. **Action Correlation**: Join with [StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) when you need the original signed `twapOrder` or `twapCancel` action
7. **Selective Storage**: Store terminal events and the last active state if you do not need every empty envelope

## Current Limitations

- **Replay History**: Available replay history varies by feed and endpoint. A cursor outside retained history returns `NOT_FOUND`
- **Schema Coverage**: The upstream lifecycle set can grow; treat documented statuses as examples, not an exhaustive list
- **Backpressure**: High-volume periods may require careful handling to avoid overwhelming downstream systems

## Resources

- **[GitHub: gRPC Code Examples](https://github.com/dwellir-public/gRPC-code-examples)** - Complete working examples
- **[GetTwapStatuses](https://www.dwellir.com/docs/hyperliquid/get_twap_statuses)** - Point-in-time TWAP status retrieval
- **[twapOrder Action Type](https://www.dwellir.com/docs/hyperliquid/twapOrder)** - TWAP order submission payloads in StreamBlocks
- **[twapCancel Action Type](https://www.dwellir.com/docs/hyperliquid/twapCancel)** - TWAP cancellation payloads in StreamBlocks

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Hyperliquid gRPC documentation](https://www.dwellir.com/docs/hyperliquid/grpc).*

---

## StreamUserFills - Stream User Fills

# StreamUserFills - Stream User Fills

`StreamUserFills` sends live fills whose own account equals the requested `user`. It does not match a counterparty, builder, or liquidated account unless that address is also the fill owner.

## Request and live-only behavior

`user` is a required 0x-prefixed address and matches case-insensitively. The zero address is accepted but has no special meaning. Empty `coins` means every coin; supplied coin identifiers match exactly, and unknown values simply never match.

The stream has no opening snapshot or backfill. Filtering can produce an empty `fills` list, but the frame remains present to preserve `sequence` continuity.

## Request Parameters

- `user` (`string, required`): Required 0x-prefixed fill-owner address, matched case-insensitively.
- `coins` (`repeated string, optional`): Optional exact coin scope; empty means all coins, and unknown coins simply never match.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamUserFills(ctx, &pb.UserFillsRequest{
        User: "0x1111111111111111111111111111111111111111",
        Coins: []string{"BTC", "ETH"},
    })
    if err != nil {
        log.Fatal(err)
    }
    var last uint64
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d sequence=%d fills=%d", update.GetBlockNumber(), update.GetSequence(), len(update.GetFills()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Source block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the first live frame.
- `fills` (`repeated Fill, required`): Fills whose own account matches user; may be empty after coin filtering.
- `fills.user` (`string, required`): Account this fill belongs to.
- `fills.coin` (`string, required`): Native coin identifier.
- `fills.px` (`string, required`): Execution price as a decimal string.
- `fills.sz` (`string, required`): Executed size as a decimal string.
- `fills.side` (`string, required`): Native side B or A.
- `fills.time` (`int64, required`): Execution time in Unix milliseconds.
- `fills.hash` (`string, required`): Transaction hash.
- `fills.tid` (`uint64, required`): Within one block, use (coin, tid). Across blocks, include the frame's block_number. Retain account and order identity for individual fills.
- `fills.crossed` (`bool, required`): True when this account was the taker.
- `fills.dir` (`string, required`): Human-readable position direction.
- `fills.start_position` (`string, required`): Signed position immediately before this fill.
- `fills.oid` (`uint64, required`): Filled order identifier.
- `fills.closed_pnl` (`string, required`): Closed profit and loss as a decimal string.
- `fills.fee` (`string, required`): Trading fee as a decimal string.
- `fills.fee_token` (`string, required`): Fee denomination.
- `fills.builder` (`FillBuilder, optional`): Builder attribution, unset for fills without a builder.
- `fills.builder.address` (`string, required`): Builder address.
- `fills.builder.fee` (`string, required`): Builder fee charged on this fill.
- `fills.cloid` (`optional string, optional`): Client order identifier when present.
- `fills.twap_id` (`optional uint64, optional`): TWAP identifier when the fill came from a TWAP order.
- `fills.liquidation` (`FillLiquidation, optional`): Liquidation metadata, unset for non-liquidation fills.
- `fills.liquidation.liquidated_user` (`string, required`): Liquidated account address.
- `fills.liquidation.mark_px` (`string, required`): Liquidation mark price.
- `fills.liquidation.method` (`string, required`): Native liquidation method.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
sequence: 1
fills: {
  user: "0x1111111111111111111111111111111111111111"
  coin: "BTC"
  px: "114250.0"
  sz: "0.25"
  side: "B"
  time: 1785736814057
  hash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  tid: 99887766
  crossed: true
  dir: "Open Long"
  start_position: "0.0"
  oid: 123456789
  closed_pnl: "0.0"
  fee: "0.285625"
  fee_token: "USDC"
  builder: { address: "0x2222222222222222222222222222222222222222" fee: "0.01" }
  cloid: "0x00112233445566778899aabbccddeeff"
  twap_id: 778899
  liquidation: { liquidated_user: "0x3333333333333333333333333333333333333333" mark_px: "114200.0" method: "market" }
}
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: The required user or a coin entry is malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: Live fills are not currently available.

### Lost live fills

- Code: `ABORTED`
- Description: Frame loss or a stream state reset ended this live-only stream.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require contiguous `sequence` values. On a gap or `ABORTED`, reconnect for new activity and recover missed blocks from [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) or durable [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data). Common live-stream errors are listed on the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service).

Related references: [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills) and [StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades).

---

## subAccounts - HyperCore Info Endpoint

# subAccounts - HyperCore Info Endpoint

Get sub-account information for a user on Hyperliquid.

Some users can return `null` for this endpoint in the Dwellir Hyperliquid Info API.
A `null` response is the safe fallback when no sub-accounts are materialized in the payload.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

Use `subAccounts` to check whether a user has associated linked trading accounts.

When integrating production workflows, always handle both `null` and empty-array
response shapes.

## Endpoint Status

For the validated sample calls, Dwellir returns `null` for accounts without active
sub-account materialization.

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state for each account
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get orders across accounts
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get fee information
- [**extraAgents**](https://www.dwellir.com/docs/hyperliquid/extra-agents) — Get agent information

## Request Parameters

- `type` (`string, required`): parameter: Must be `"subAccounts"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "subAccounts",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
null
```

***

*Manage your Hyperliquid sub-accounts with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## subAccountModify payload - Sub-Account Settings

# subAccountModify payload - Sub-Account Settings

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `subAccountModify` payload records a settings or permissions change for a Hyperliquid sub-account.

## Sample Data

```json
{
  "signature": {
    "r": "0xa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
    "s": "0x6543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba987",
    "v": 27
  },
  "action": {
    "type": "subAccountModify",
    "subAccountUser": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Trading Bot 1"
  },
  "nonce": 1767949700000
}
```

## Field Reference

### Action Fields

| Field            | Type   | Description                   |
| ---------------- | ------ | ----------------------------- |
| `type`           | string | Always `"subAccountModify"`   |
| `subAccountUser` | string | Sub-account address to modify |
| `name`           | string | New name for the sub-account  |

## Use Cases

### Sub-Account Management

Track sub-account modifications:

```python
def process_subAccountModify_action(action):
    sub_account = action.get('subAccountUser')
    name = action.get('name')
    print(f"Sub-account modified: {sub_account[:10]}... -> {name}")
```

## Related Action Payloads

- [createSubAccount](https://www.dwellir.com/docs/hyperliquid/createSubAccount) - Sub-account creation
- [subAccountTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountTransfer) - Sub-account funding transfers

---

## subAccountSpotTransfer payload - Sub-Account Spot Transfers

# subAccountSpotTransfer payload - Sub-Account Spot Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `subAccountSpotTransfer` payload records a spot-token transfer between a master account and one of its sub-accounts.

## Sample Data

```json
{
  "signature": {
    "r": "0xd37da2735026576e0cfcd347f381499e142423edae6ce9a170fe985bd99f7aaf",
    "s": "0x2999636e5fb176a4ae4d3cb1c4682496fcd0bd2b79e84497865340dfeb02c801",
    "v": 27
  },
  "action": {
    "type": "subAccountSpotTransfer",
    "subAccountUser": "0x9266865bb6afb4c4f618544dd3b8c970f17aa664",
    "isDeposit": true,
    "token": "BZEC:0x33b2c5252e8ea8431808129c41668129",
    "amount": "4.63"
  },
  "nonce": 1767952944523
}
```

## Field Reference

### Action Fields

| Field            | Type    | Description                                           |
| ---------------- | ------- | ----------------------------------------------------- |
| `type`           | string  | Always `"subAccountSpotTransfer"`                     |
| `subAccountUser` | string  | Sub-account address                                   |
| `isDeposit`      | boolean | `true` to deposit to sub-account, `false` to withdraw |
| `token`          | string  | Token identifier                                      |
| `amount`         | string  | Amount to transfer                                    |

## Use Cases

### Sub-Account Spot Funding

Track spot token allocations to sub-accounts:

```python
def process_subAccountSpotTransfer_action(action):
    sub_account = action.get('subAccountUser')
    token = action.get('token').split(':')[0]
    amount = action.get('amount')
    direction = 'to' if action.get('isDeposit') else 'from'
    print(f"Spot transfer: {amount} {token} {direction} sub-account")
```

## Related Action Payloads

- [subAccountTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountTransfer) - USD transfers
- [spotSend](https://www.dwellir.com/docs/hyperliquid/spotSend) - Direct spot transfers

---

## subAccountTransfer payload - Sub-Account Transfers

# subAccountTransfer payload - Sub-Account Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `subAccountTransfer` payload records a USD transfer between a master account and one of its sub-accounts.

## Sample Data

```json
{
  "signature": {
    "r": "0xda5441ff957c27e824e3540bcfb3e0bb7ccf5fba10712084981e14b6822e5d2b",
    "s": "0x36985abcf5691e89d37afd7f9da70453bc7abdd4f0b29c1ddd9326022c94a43c",
    "v": 28
  },
  "action": {
    "type": "subAccountTransfer",
    "subAccountUser": "0xde22d34aa3b215d225e209c906e19511465738b1",
    "isDeposit": true,
    "usd": 18000000
  },
  "nonce": 1768146973096
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x8b7eafe317b159a08cf804332647b702033800c8b2b478722f475b35d6b5338b)

## Field Reference

### Action Fields

| Field            | Type    | Description                                                             |
| ---------------- | ------- | ----------------------------------------------------------------------- |
| `type`           | string  | Always `"subAccountTransfer"`                                           |
| `subAccountUser` | string  | Address of the sub-account                                              |
| `isDeposit`      | boolean | `true` to transfer to sub-account, `false` to withdraw from sub-account |
| `usd`            | number  | Amount in raw units (6 decimals, so 153000000 = 153 USD)                |

## Amount Conversion

The `usd` field uses 6 decimal places:

- `153000000` = 153.00 USD
- `1000000000` = 1,000.00 USD

## Use Cases

### Capital Allocation Tracking

Monitor how traders allocate capital across sub-accounts:

```python
def process_subAccountTransfer_action(action):
    sub_account = action.get('subAccountUser')
    amount = action.get('usd') / 1_000_000
    direction = 'to' if action.get('isDeposit') else 'from'

    print(f"Transfer ${amount:,.2f} {direction} sub-account {sub_account[:10]}...")
```

### Strategy Isolation Analysis

Track how traders segment capital for different trading strategies.

### Risk Management Patterns

Monitor sub-account funding to understand risk management approaches.

## Related Action Payloads

- [createSubAccount](https://www.dwellir.com/docs/hyperliquid/createSubAccount) - Sub-account creation
- [subAccountModify](https://www.dwellir.com/docs/hyperliquid/subAccountModify) - Sub-account setting changes
- [subAccountSpotTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountSpotTransfer) - Sub-account spot transfers

---

## Tick Data - Historical Trade Executions

# Tick Data - Historical Trade Executions

Processed Hyperliquid trade-execution records derived from `node_fills_by_block` and shaped for analysis workflows.

## What is Tick Data?

Tick data represents individual execution rows rather than aggregated OHLCV bars. Each available row preserves source timing, size, and side for higher-resolution market analysis.

**Source:** Processed from the `node_fills_by_block` generation of the [archival fill data in the S3 Bucket](https://www.dwellir.com/docs/hyperliquid/historical-data#archive-formats), available from `2025-07-27` to today. Confirm processed availability for requested symbols and dates with support.

## Processed Tick Data Schema

Dwellir processes `node_fills_by_block` into a simplified tick format optimized for analysis:

```
timestamp, pair, price, size, side, trade_id, user_address, block_number
```

| Field          | Type         | Description                                              |
| -------------- | ------------ | -------------------------------------------------------- |
| `timestamp`    | milliseconds | Trade execution time (from `time` field)                 |
| `pair`         | string       | Trading pair (from `coin` field, e.g., BTC-PERP)         |
| `price`        | decimal      | Execution price (from `px`)                              |
| `size`         | decimal      | Trade size (from `sz`)                                   |
| `side`         | string       | Buy (B) or Ask (A)                                       |
| `trade_id`     | integer      | Source trade ID; group globally by `pair` and `trade_id` |
| `user_address` | hex          | User wallet address                                      |
| `block_number` | integer      | Block height for sequencing                              |

### Timestamp Precision

Timestamps are recorded in milliseconds from the source `time` field. Order rows by `block_number` and `timestamp`; use `(pair, trade_id)` when grouping or deduplicating matches rather than assuming trade IDs are sequential or globally unique.

### Example Records

CSV
JSON
Parquet Schema

```csv
timestamp,pair,price,size,side,trade_id,user_address,block_number
1753606210273,BTC-PERP,118136.0,0.00009,B,161270588369408,0x7839e2f2c375dd2935193f2736167514efff9916,676607012
1753606210274,BTC-PERP,118136.5,0.00025,B,161270588369409,0xa68c548f3acd23a7fe3e867cc47f302559794419,676607012
1753606210275,BTC-PERP,118135.8,0.00010,A,161270588369410,0x5ac99df645f3414876c816caa18b2d234024b487,676607013
```

```json
[
  {
    "timestamp": 1753606210273,
    "pair": "BTC-PERP",
    "price": "118136.0",
    "size": "0.00009",
    "side": "B",
    "trade_id": 161270588369408,
    "user_address": "0x7839e2f2c375dd2935193f2736167514efff9916",
    "block_number": 676607012
  },
  {
    "timestamp": 1753606210274,
    "pair": "BTC-PERP",
    "price": "118136.5",
    "size": "0.00025",
    "side": "B",
    "trade_id": 161270588369409,
    "user_address": "0xa68c548f3acd23a7fe3e867cc47f302559794419",
    "block_number": 676607012
  }
]
```

```
message tick_data {
  required int64 timestamp;
  required binary pair (UTF8);
  required double price;
  required double size;
  required binary side (UTF8);
  required int64 trade_id;
  required binary user_address (UTF8);
  required int64 block_number;
}
```

## Extended Fields (Optional)

For advanced use cases, additional fields from the source data can be included:

| Field        | Description                                    |
| ------------ | ---------------------------------------------- |
| `dir`        | Trade direction (Open Long, Close Short, etc.) |
| `closedPnl`  | Realized PnL from closed positions             |
| `fee`        | Trading fee                                    |
| `crossed`    | Whether order crossed the spread               |
| `builder`    | Block builder address                          |
| `builderFee` | Fee paid to builder                            |

## Data Volume

Hyperliquid processes significant trading volume. Typical daily volumes:

| Metric                       | Approximate Value |
| ---------------------------- | ----------------- |
| Daily trades                 | 5-15 million      |
| Daily file size (compressed) | 500MB - 2GB       |
| Peak trades per second       | 10,000+           |

Parquet format recommended for datasets larger than 1GB due to compression efficiency and columnar query performance.

## Available Formats

| Format      | Compression | Best For                               |
| ----------- | ----------- | -------------------------------------- |
| **CSV**     | Gzip        | Quick analysis, streaming ingestion    |
| **Parquet** | Snappy/Zstd | Large-scale analysis, columnar queries |

## Delivery Options

| Method            | Status               | Description                                       |
| ----------------- | -------------------- | ------------------------------------------------- |
| **Bulk Download** | Confirm with support | Requested historical exports and delivery cadence |
| **REST API**      | Coming Soon          | Query-based access with filtering                 |

## Use Cases

### Backtesting Execution Strategies

Test execution algorithms against real historical fills. Measure expected slippage, fill rates, and execution quality at specific order sizes.

### Slippage Analysis

Calculate actual slippage for different order sizes and market conditions. Build slippage models for execution cost estimation.

### Market Impact Modelling

Study how order flow affects prices. Measure temporary and permanent impact for different trade sizes and market states.

### Address Tracking and Flow Analysis

Identify large traders and track their activity patterns. Monitor address-level flow for market intelligence.

### Cumulative Delta Analysis

Compute buy/sell volume imbalances in real-time. Track order flow momentum and divergences.

## Derived Metrics

In addition to raw tick data, derived metrics are available:

| Metric                | Description                                   |
| --------------------- | --------------------------------------------- |
| **Buy/Sell Volume**   | Per-interval volume breakdown by side         |
| **Large Trade Flags** | Trades exceeding configurable size thresholds |
| **Cumulative Delta**  | Running sum of signed volume                  |
| **VWAP**              | Volume-weighted average price per interval    |

## Sample Data

Ask support whether a sample dataset is available for your requested symbols, dates, and schema.

**Sample Contents:**

- Example time window and symbols
- Confirmed core or extended fields
- Requested delivery format

Contact <support@dwellir.com> to request sample data.

## Related Data Products

| Need                   | Recommendation                                                           |
| ---------------------- | ------------------------------------------------------------------------ |
| Aggregated price bars  | [OHLCV Data](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index/ohlcv-data)             |
| Raw source data        | [Historical Data](https://www.dwellir.com/docs/hyperliquid/historical-data)                     |
| Real-time trade stream | [Order Book Server - Trades](https://www.dwellir.com/docs/hyperliquid/trades) |

## Data Quality

- **Ordering and identity**: Order by block and time; group or deduplicate using `(pair, trade_id)`
- **Timestamp Accuracy**: Millisecond precision from source `time` field

## Access

Contact the Dwellir team for tick data access:

**Email**: <support@dwellir.com>

Include in your request:

- Symbols required (or "all perpetuals")
- Date range
- Preferred format (CSV or Parquet)
- Fields needed (core or extended)
- Filtering requirements (optional: size thresholds, specific addresses)
- Delivery preference (bulk download or streaming)

---

## tokenDelegate payload - Validator Delegation

# tokenDelegate payload - Validator Delegation

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `tokenDelegate` payload records a token delegation or undelegation involving a Hyperliquid validator.

## Sample Data

```json
{
  "signature": {
    "r": "0xd3d8ea7bf5d7699274f77d6527be0a78f137cb7f41e8b90b87de639b1f4d5704",
    "s": "0x7041f94160b4b38e516507a201e5f65872fb7e9ce2522b901b31621048fbb653",
    "v": 27
  },
  "action": {
    "type": "tokenDelegate",
    "signatureChainId": "0xa4b1",
    "hyperliquidChain": "Mainnet",
    "validator": "0xa23b4556090260828ff3f939d2dbdd4f318b5f1f",
    "wei": 10000000000,
    "isUndelegate": false,
    "nonce": 1768148103446
  },
  "nonce": 1768148103446
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x9dc715cc0bc6509b9f400433267e8b0201fd00b1a6c96f6d418fc11ecaca2a86)

## Field Reference

### Action Fields

| Field              | Type    | Description                               |
| ------------------ | ------- | ----------------------------------------- |
| `type`             | string  | Always `"tokenDelegate"`                  |
| `signatureChainId` | string  | Chain ID for EIP-712 signing              |
| `hyperliquidChain` | string  | Target chain: `"Mainnet"` or `"Testnet"`  |
| `validator`        | string  | Validator address to delegate to          |
| `wei`              | number  | Amount in wei (smallest unit)             |
| `isUndelegate`     | boolean | `true` to undelegate, `false` to delegate |
| `nonce`            | number  | Transaction nonce                         |

## Amount Conversion

The `wei` field is in the smallest token unit:

- `14494791496000` wei = 14.49 tokens (assuming 12 decimals)

## Use Cases

### Staking Analytics

Track delegation and undelegation patterns:

```python
def process_tokenDelegate_action(action):
    validator = action.get('validator')
    amount_wei = action.get('wei')
    is_undelegate = action.get('isUndelegate')

    direction = 'undelegated from' if is_undelegate else 'delegated to'
    print(f"Tokens {direction} validator {validator[:10]}...")
```

### Validator Monitoring

Track which validators are gaining or losing stake.

### Network Security Analysis

Monitor total stake and distribution across validators.

## Related Action Payloads

- [claimRewards](https://www.dwellir.com/docs/hyperliquid/claimRewards) - Staking reward claims
- [voteAppHash](https://www.dwellir.com/docs/hyperliquid/voteAppHash) - Validator voting

---

## trace_block - Hyperliquid RPC Method

# trace_block - Hyperliquid RPC Method

Returns traces for all transactions in a block on Hyperliquid.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Hyperliquid
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Hyperliquid chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/hyperliquid/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/hyperliquid/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/hyperliquid/trace_get) - Get a specific trace by index

---

## trace_call - Hyperliquid RPC Method

# trace_call - Hyperliquid RPC Method

Traces a call without creating a transaction on Hyperliquid, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Hyperliquid
- **Pre-execution analysis** - Test contract interactions without spending gas for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea",
      "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea", "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
    data: '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea',
        'data': '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/hyperliquid/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/hyperliquid/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/hyperliquid/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Hyperliquid RPC Method

# trace_callMany - Hyperliquid RPC Method

Traces multiple calls in sequence on Hyperliquid, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Hyperliquid
- **Historical state comparison** - Compare how the same call would execute at different points in Hyperliquid chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea", "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"}, ["trace"]],
      [{"to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea", "data": "0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea"}, ["trace"]],
        [{"to": "0x30e54c9bc205e19d693d53c0b0be92299d4191ea", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea', data: '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea' }, ['trace']],
    [{ to: '0x30e54c9bc205e19d693d53c0b0be92299d4191ea', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea', 'data': '0x70a0823100000000000000000000000030e54c9bc205e19d693d53c0b0be92299d4191ea'}, ['trace']],
        [{'to': '0x30e54c9bc205e19d693d53c0b0be92299d4191ea', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/hyperliquid/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/hyperliquid/eth_call) - Execute call without trace

---

## trace_filter - Hyperliquid RPC Method

# trace_filter - Hyperliquid RPC Method

Returns traces matching a filter on Hyperliquid.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Hyperliquid
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x30e54c9bc205e19d693d53c0b0be92299d4191ea"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x30e54c9bc205e19d693d53c0b0be92299d4191ea"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x30e54c9bc205e19d693d53c0b0be92299d4191ea'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x30e54c9bc205e19d693d53c0b0be92299d4191ea'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/hyperliquid/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/hyperliquid/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/hyperliquid/eth_getLogs) - Filter event logs

---

## trace_get - Hyperliquid RPC Method

# trace_get - Hyperliquid RPC Method

Returns a trace at a specific position within a transaction on Hyperliquid.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Hyperliquid
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/hyperliquid/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/hyperliquid/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Hyperliquid RPC Method

# trace_replayBlockTransactions - Hyperliquid RPC Method

Replays all transactions in a block on Hyperliquid and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Hyperliquid
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Hyperliquid chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/hyperliquid/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/hyperliquid/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/hyperliquid/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Hyperliquid RPC Method

# trace_replayTransaction - Hyperliquid RPC Method

Replays a transaction on Hyperliquid and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Hyperliquid
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/hyperliquid/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/hyperliquid/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/hyperliquid/trace_block) - Get all traces in a block

---

## trace_transaction - Hyperliquid RPC Method

# trace_transaction - Hyperliquid RPC Method

Returns all traces for a specific transaction on Hyperliquid.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Hyperliquid
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x090cd1f41962604b7efbc2b3c93b536dc7716c8c3487bfe2ba3ff4fe57df0614'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/hyperliquid/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/hyperliquid/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/hyperliquid/trace_filter) - Filter traces by criteria

---

## Trades Stream - Real-Time Trade Executions

# Trades Stream - Real-Time Trade Executions

Stream real-time trade executions as they occur on Hyperliquid. Each trade message contains the execution price, size, direction (buy/sell), timestamp, and participant wallet addresses.

Clone our complete examples: [github.com/dwellir-public/hyperliquid-orderbook-server-code-examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)

## How to Subscribe

Send a subscription message to the WebSocket endpoint:

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "trades",
    "coin": "BTC"
  }
}
```

### Subscription Parameters

| Parameter | Type   | Required | Description                                                                          |
| --------- | ------ | -------- | ------------------------------------------------------------------------------------ |
| `type`    | string | Yes      | Must be `"trades"`                                                                   |
| `coin`    | string | Yes      | Trading pair symbol (e.g., `"BTC"`, `"ETH"`, `"xyz:MSTR"`, `"@150"`)                 |
| `user`    | string | No       | Filter trades to only those involving a specific wallet address (e.g., `"0xabc..."`) |

For HIP3 (permissionless perpetuals) markets, use the full coin label format with the `xyz:` prefix. For example, use `"xyz:MSTR"` for the MicroStrategy perpetual, not just `"MSTR"`. Standard perpetuals like BTC and ETH do not require a prefix.

For spot markets, use the `@{index}` format where the index is the spot asset index. For example, use `"@150"` for a specific spot market.

### User Filtering

You can filter the trades stream to only receive trades involving a specific wallet address. This is useful for tracking your own executions or monitoring a specific trader's activity without processing the full trade firehose.

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "trades",
    "coin": "BTC",
    "user": "0x1ed8d101622beaf192d06137dfb220851bcad9fa"
  }
}
```

When the `user` field is provided, only trades where the specified address appears in the `users` array (as either buyer or seller) are delivered. The `user` field is optional. Omitting it returns all trades for the coin, as before.

The first websocket message after subscribing is a `subscriptionResponse`; subsequent messages carry the `trades` channel payloads.

## Request Parameters

- `type` (`string, required`): Subscription parameter: Must be `"trades"`
- `coin` (`string, required`): Subscription parameter: Trading pair symbol (e.g., `"BTC"`, `"ETH"`, `"xyz:MSTR"`, `"@150"`)
- `user` (`string, optional`): Subscription parameter: Filter trades to only those involving a specific wallet address (e.g., `"0xabc..."`)

## Request Example

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "trades",
    "coin": "BTC"
  }
}
```

## Response Fields

- `channel` (`string, required`): Always `"trades"` for this subscription type
- `data` (`array, required`): Array of trade objects (may contain multiple trades per message)
- `coin` (`string, required`): Trading pair symbol
- `side` (`string, required`): `"A"` = Ask (sell/taker sold), `"B"` = Bid (buy/taker bought)
- `px` (`string, required`): Execution price
- `sz` (`string, required`): Trade size in base currency
- `time` (`number, required`): Unix timestamp in milliseconds
- `hash` (`string, required`): Transaction hash on Hyperliquid. Zero-hash (`0x000...000`) indicates a [TWAP fill](#zero-hash-trades-twap-fills) with no on-chain transaction.
- `tid` (`number, required`): Unique trade ID
- `users` (`array, required`): Array of two wallet addresses: `[buyer, seller]`

## Successful Response

```json
{
  "channel": "trades",
  "data": [
    {
      "coin": "BTC",
      "side": "B",
      "px": "90058.0",
      "sz": "0.00012",
      "hash": "0x0a4cc891f222c1cf0bc60432f4991e02013400778d25e0a1ae1573e4b1269bb9",
      "time": 1767878803102,
      "tid": 907188554740561,
      "users": [
        "0xb08ed6f6ad7b22138d4db6d0549efcf1f5e51767",
        "0x13558be785661958932ceac35ba20de187275a42"
      ]
    }
  ]
}
```

## Response Field Reference

| Field     | Type   | Description                                                                                                                                    |
| --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `channel` | string | Always `"trades"` for this subscription type                                                                                                   |
| `data`    | array  | Array of trade objects (may contain multiple trades per message)                                                                               |
| `coin`    | string | Trading pair symbol                                                                                                                            |
| `side`    | string | `"A"` = Ask (sell/taker sold), `"B"` = Bid (buy/taker bought)                                                                                  |
| `px`      | string | Execution price                                                                                                                                |
| `sz`      | string | Trade size in base currency                                                                                                                    |
| `time`    | number | Unix timestamp in milliseconds                                                                                                                 |
| `hash`    | string | Transaction hash on Hyperliquid. Zero-hash (`0x000...000`) indicates a [TWAP fill](#zero-hash-trades-twap-fills) with no on-chain transaction. |
| `tid`     | number | Unique trade ID                                                                                                                                |
| `users`   | array  | Array of two wallet addresses: `[buyer, seller]`                                                                                               |

### Understanding the `side` Field

The `side` field indicates which side of the order book the trade executed against:

- **`"A"` (Ask)**: The taker sold into the bid. A market sell order matched with a resting buy order.
- **`"B"` (Bid)**: The taker bought from the ask. A market buy order matched with a resting sell order.

## Use Cases

### Trade Flow Analysis

Monitor real-time trade executions to understand market momentum:

- **Direction detection**: Track whether buyers or sellers are dominating
- **Large trade alerts**: Identify whale activity by filtering on size
- **Execution timing**: Measure latency between your orders and confirmations

### VWAP and TWAP Calculations

Build execution benchmarks from the trade stream:

- **VWAP**: Volume-weighted average price for execution quality analysis
- **TWAP**: Time-weighted average price for order slicing strategies
- **Implementation shortfall**: Compare your fills against market VWAP

### Historical Trade Recording

Capture trade data for backtesting and research:

- **Tick data collection**: Store every trade for historical analysis
- **Pattern recognition**: Train ML models on trade sequences
- **Market replay**: Reconstruct market conditions for strategy testing

### Wallet Tracking

Use the `users` field to monitor specific addresses. For dedicated tracking, use the [`user` subscription filter](#user-filtering) to receive only trades involving a specific wallet. This is more efficient than filtering client-side.

- **Whale watching**: Alert when known large traders execute
- **Copy trading signals**: Track successful trader activity
- **Smart money flow**: Analyze institutional wallet behavior
- **Execution monitoring**: Track your own fills by filtering on your wallet address

## Zero-Hash Trades (TWAP Fills)

Some trades on Hyperliquid carry a zero transaction hash:

```
0x0000000000000000000000000000000000000000000000000000000000000000
```

These are typically **TWAP (Time-Weighted Average Price) fills**. TWAP orders split large executions into smaller slices over time. The matching engine generates these fills internally, so they do not correspond to user-signed L1 transactions and have no on-chain hash.

Zero-hash trades are valid executions with accurate price, size, and participant data. Only the `hash` field differs from regular trades.

Zero-hash trades appear at identical rates on the public Hyperliquid API. Dwellir passes through the `hash` field from the Hyperliquid node without modification.

## Subscription Management

### Multiple Coin Subscriptions

Subscribe to multiple trading pairs on a single connection:

```python
coins = ["BTC", "ETH", "SOL", "ARB"]

for coin in coins:
    await websocket.send(json.dumps({
        "method": "subscribe",
        "subscription": {
            "type": "trades",
            "coin": coin
        }
    }))
```

### Unsubscribe

Stop receiving trades for a specific coin:

```json
{
  "method": "unsubscribe",
  "subscription": {
    "type": "trades",
    "coin": "BTC"
  }
}
```

## Get Access

Ready to integrate real-time Hyperliquid trade data?

- **[Volume Calculator](https://www.dwellir.com/hyperliquid-orderbook#calculator)** - Estimate monthly message volume
- **[Contact Sales](mailto:support@dwellir.com)** - Get your WebSocket credentials
- **[Dashboard](https://dashboard.dwellir.com)** - Manage your subscription

***

*Stream institutional-grade Hyperliquid trade data with Dwellir's ultra-low latency infrastructure.*

---

## Hyperliquid gRPC and WebSocket troubleshooting

# Hyperliquid gRPC and WebSocket troubleshooting

Start with the endpoint and subscription type. HyperEVM, HyperCore Info, order-book WebSocket, and gRPC expose different APIs.

## Which endpoint should I use?

| Workload                                           | Use                                                                     |
| -------------------------------------------------- | ----------------------------------------------------------------------- |
| EVM balances, contracts, logs, or transactions     | The HyperEVM JSON-RPC endpoint in the dashboard                         |
| Current HyperCore account state or market metadata | [Info endpoint](https://www.dwellir.com/docs/hyperliquid/info-endpoint)                        |
| Live L2/L4 books, best bid and offer, or trades    | [Order Book WebSocket](https://www.dwellir.com/docs/hyperliquid/order-book-server)             |
| Raw blocks, fills, order events, or TWAP events    | [V3 gRPC raw feeds](https://www.dwellir.com/docs/hyperliquid/grpc)                             |
| Pre-consensus mempool transactions                 | [StreamMempoolTxs](https://www.dwellir.com/docs/hyperliquid/stream_mempool_txs)                |
| Typed live market subscriptions                    | [V3 market streams](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service) |
| Historical queries and processed datasets          | [Hyperliquid Index](https://www.dwellir.com/docs/hyperliquid/hyperliquid-index)                |
| Native historical files and replay inputs          | [Historical archive](https://www.dwellir.com/docs/hyperliquid/historical-data)                 |
| Gossip connectivity for your own node              | [Peering](https://www.dwellir.com/docs/hyperliquid/peering)                                    |

An `eth_subscribe` request belongs to HyperEVM JSON-RPC. An `l4Book` subscription belongs to the order-book service.

Use the endpoint's documented authentication. gRPC uses TLS and `x-api-key` metadata. WebSocket and HTTP connection examples appear in their respective references.

## Why does a symbol return no data?

Use the exact market identifier, including case and any decentralized exchange prefix. A HIP-3 market such as `xyz:TSLA` is distinct from an unprefixed symbol.

Discover perpetual markets with [meta](https://www.dwellir.com/docs/hyperliquid/meta), deployed exchanges with [perpDexs](https://www.dwellir.com/docs/hyperliquid/perp-dexs), and spot markets with [spotMeta](https://www.dwellir.com/docs/hyperliquid/spot-meta).

Specify the relevant exchange when the Info method requires it. A human-readable ticker is not always the feed's market identifier.

Current metadata describes current markets. Historical research needs metadata from the period under study, including listings, delistings, and asset-index mappings.

## Can I subscribe to several markets with one key?

Yes. Send separate subscriptions on the order-book WebSocket connection using each subscription's documented parameters.

V3 gRPC methods use their own coin selectors. Check the method reference before moving a WebSocket subscription shape into gRPC.

Using several keys or connections does not multiply an account's shared throughput limit. See [request counting](https://www.dwellir.com/docs/getting-started/rate-limits#request-counting).

## Why is a filtered gRPC stream quiet or disconnected?

V3 raw-feed filters skip records with zero matching events. Silence can mean that the selected user or market has no matching events.

HTTP/2 keepalive pings test connection liveness; they do not create matching application records. Raw streams carry no heartbeat frames unless they opt in to [progress frames](https://www.dwellir.com/docs/hyperliquid/grpc#progress-frames), which keep a quiet filtered stream open and advance its resume cursor through filtered-out blocks.

An intermediary can enforce a response idle timeout even when transport keepalive succeeds. A `504` alone does not prove that your filter is invalid.

Check the client deadline, proxy timeout, and gRPC status. Compare a short unfiltered stream with the same feed to separate filter silence from feed inactivity.

Reconnect with backoff after transient failures. Use the last processed cursor when the method supports replay; a progress frame's `scanned_through` is a valid cursor.

## How do I resume without losing or double-counting records?

V3 raw-feed positions are inclusive. Resume from the last processed `Record.block_number` or `Record.timestamp`, or from a progress frame's `scanned_through`, then deduplicate the repeated record.

Commit a cursor after processing and storing the whole record. Preserve event identity within each block when downstream writes can partially succeed.

Cursor fields are optional. Do not invent a zero cursor when metadata is absent.

Replay retention varies by feed and endpoint. `NOT_FOUND` can mean the requested position is outside retained history; use the [archive](https://www.dwellir.com/docs/hyperliquid/historical-data) for older data.

Typed market streams are live-only. After an L2/L4 disconnect, resubscribe and rebuild from the opening snapshot before applying new diffs.

WebSocket subscriptions belong to a connection. Send them again after reconnecting. A new connection does not inherit previous subscriptions.

## Why is the connection fast but the data old?

Measure connection time and data freshness separately. A fast handshake does not establish the age of a snapshot or update.

Record the source block timestamp, block number, and your local receipt time. Synchronize your clock before calculating wall-clock lag.

Compare the same market and block across sources. A difference in arrival time can come from source state, replay, processing, or the network path.

An old opening snapshot requires updates to reach current state. If updates stop, reconnect and rebuild the book rather than trading on stale state.

## How is streaming usage counted?

Each delivered gRPC message counts toward metered usage. Message count differs from fill count because one raw record can contain several events.

WebSocket usage includes sent and received messages. Several subscriptions can increase usage through several delivered updates.

Filtering reduces delivered matching records. It does not multiply your account's limit or extend replay retention.

For method-specific counting, see [rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) and the selected API reference.

## Does peering provide the same service as an API subscription?

No. Peering provides gossip connectivity for a node you operate. Your node still needs its own storage, synchronization, and local API services.

Reserved peers carry blocks and the full mempool. They do not promise validator priority or an earlier view than every other subscriber.

The two reserved peers use separate hosts in one selected region. This provides host redundancy; it does not provide geographic redundancy.

See [peering requirements and setup](https://www.dwellir.com/docs/hyperliquid/peering) for static public IP addresses, ports, and node configuration.

## How do I validate a historical research dataset?

Use [archive research and validation](https://www.dwellir.com/docs/hyperliquid/research). It covers manifests, timestamps, TWAP joins, liquidations, snapshots, account state, and data-use rights.

For access and HTTP errors, use [RPC troubleshooting](https://www.dwellir.com/docs/getting-started/troubleshooting).

---

## twapCancel payload - TWAP Cancellations

# twapCancel payload - TWAP Cancellations

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `twapCancel` payload records cancellation of an active time-weighted average price order.

## Sample Data

```json
{
  "signature": {
    "r": "0x19049f59f4a558ebde3cd54b7fec8fa7329bed21515aafa468f08b6d283f87d5",
    "s": "0x701715161c404203ec40441689c4fea25894c827a8bf48d3a46a9601d859478a",
    "v": 27
  },
  "action": {
    "type": "twapCancel",
    "a": 161,
    "t": 1506780
  },
  "nonce": 1768147413037,
  "expiresAfter": 1768147429667
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x93986f25f267ac6b95120433265d72020334000b8d6acb3d37611a78b16b8656)

## Field Reference

### Action Fields

| Field  | Type   | Description             |
| ------ | ------ | ----------------------- |
| `type` | string | Always `"twapCancel"`   |
| `a`    | number | Asset index             |
| `t`    | number | TWAP order ID to cancel |

## Use Cases

### TWAP Lifecycle Tracking

Monitor TWAP order cancellations:

```python
def process_twapCancel_action(action):
    asset = action.get('a')
    twap_id = action.get('t')
    print(f"TWAP cancelled: asset {asset}, id {twap_id}")
```

## Related Action Payloads

- [twapOrder](https://www.dwellir.com/docs/hyperliquid/twapOrder) - TWAP order payloads
- [cancel](https://www.dwellir.com/docs/hyperliquid/cancel) - Regular order cancellations

---

## twapOrder payload - TWAP Orders

# twapOrder payload - TWAP Orders

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `twapOrder` payload records a time-weighted average price order and its execution parameters.

## Sample Data

```json
{
  "signature": {
    "r": "0xec414de7c86d85e3c73aba1ed8496e15f48acb37ec7f9b52a1c7d76f091ccd45",
    "s": "0x373d79f4d9731a69b4d93ccebf3fa711eae9550be65878c9358f30b20e798e4b",
    "v": 28
  },
  "action": {
    "type": "twapOrder",
    "twap": {
      "a": 10260,
      "b": true,
      "s": "215.72",
      "r": false,
      "m": 1440,
      "t": false
    }
  },
  "nonce": 1768146926099
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x65ce2950fb88ebd16747043326457a02016e0036968c0aa30996d4a3ba8cc5bc)

## Field Reference

### Action Fields

| Field  | Type    | Description                                      |
| ------ | ------- | ------------------------------------------------ |
| `type` | string  | Always `"twapOrder"`                             |
| `a`    | number  | Asset index (e.g., 0 = BTC)                      |
| `b`    | boolean | Side: `true` for buy, `false` for sell           |
| `s`    | string  | Total size to execute                            |
| `r`    | boolean | Reduce-only flag                                 |
| `m`    | number  | Duration in minutes                              |
| `t`    | boolean | Randomize execution (avoid predictable patterns) |

## TWAP Execution

TWAP orders:

- Split total size into smaller child orders
- Execute over the specified duration
- Can be randomized to avoid detection
- Minimize market impact for large positions

## Use Cases

### Institutional Order Detection

Track TWAP order submissions for large position building:

```python
def process_twapOrder_action(action):
    asset = action.get('a')
    side = 'BUY' if action.get('b') else 'SELL'
    size = action.get('s')
    duration = action.get('m')

    print(f"TWAP: {side} {size} of asset {asset} over {duration} minutes")
```

### Market Impact Analysis

Monitor TWAP activity to understand institutional positioning.

### Execution Quality Research

Study TWAP execution patterns and slippage.

## Related Action Payloads

- [twapCancel](https://www.dwellir.com/docs/hyperliquid/twapCancel) - TWAP cancellations
- [order](https://www.dwellir.com/docs/hyperliquid/order) - Standard orders
- [batchModify](https://www.dwellir.com/docs/hyperliquid/batchModify) - Batch modifications

---

## updateIsolatedMargin payload - Isolated Margin Updates

# updateIsolatedMargin payload - Isolated Margin Updates

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `updateIsolatedMargin` payload records margin added to or removed from an isolated position.

## Sample Data

```json
{
  "signature": {
    "r": "0xd14b53f9f6b7cb39e5289f62c453f22d21d46def6f7acbc267cb33f1d2d2668f",
    "s": "0x393d89fcd7835fad35ff2b06e29b6c56bd8034efc5bd9b38848c8ac7dd32fbc3",
    "v": 28
  },
  "action": {
    "type": "updateIsolatedMargin",
    "asset": 0,
    "isBuy": true,
    "ntli": -1000000
  },
  "nonce": 1768146925098
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xd02fc36287650ca2d1a9043326463302037f004822682b7473f86eb54668e68d)

## Field Reference

### Action Fields

| Field   | Type    | Description                                                        |
| ------- | ------- | ------------------------------------------------------------------ |
| `type`  | string  | Always `"updateIsolatedMargin"`                                    |
| `asset` | number  | Asset index (e.g., 0 = BTC)                                        |
| `isBuy` | boolean | Position side: `true` for long, `false` for short                  |
| `ntli`  | number  | Margin adjustment in raw units (negative = remove, positive = add) |

## Understanding ntli

The `ntli` field represents the margin change in raw integer units:

- **Positive values**: Add margin to the position (reduce liquidation risk)
- **Negative values**: Remove margin from the position (increase liquidation risk)

The value `-1000000` in the sample represents removing 1 USD of margin (assuming 6 decimal places for USDC).

## Use Cases

### Position Risk Monitoring

Track margin adjustments to understand how traders manage position risk:

```python
def process_updateIsolatedMargin_action(action):
    asset = action.get('asset')
    side = 'LONG' if action.get('isBuy') else 'SHORT'
    margin_change = action.get('ntli') / 1_000_000  # Convert to USD

    direction = 'added' if margin_change > 0 else 'removed'
    print(f"Margin {direction}: {abs(margin_change)} USD on {side} {asset}")
```

### Liquidation Prevention Analysis

Monitor margin additions that may indicate positions approaching liquidation.

### Capital Efficiency Tracking

Track margin removals to understand how traders optimize capital usage.

## Related Action Payloads

- [updateLeverage](https://www.dwellir.com/docs/hyperliquid/updateLeverage) - Leverage-setting changes
- [userPortfolioMargin](https://www.dwellir.com/docs/hyperliquid/userPortfolioMargin) - Portfolio margin mode

---

## updateLeverage payload - Leverage Updates

# updateLeverage payload - Leverage Updates

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `updateLeverage` payload records a leverage-setting change for a specific asset position.

## Sample Data

```json
{
  "signature": {
    "r": "0x10b0a002706afea1c9e337ac501fd52a96fb8ddad544b2b6a3a663e0c2e16e51",
    "s": "0x5906914d9c472e585e13b52e9435fb1d9980022d625559b566a3541c0f92d5a2",
    "v": 28
  },
  "action": {
    "type": "updateLeverage",
    "asset": 110000,
    "isCross": false,
    "leverage": 7
  },
  "nonce": 1768146912541
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x909ba690b7305579921504332644be02028d00765233744b346451e376342f64)

## Field Reference

### Action Fields

| Field      | Type    | Description                                          |
| ---------- | ------- | ---------------------------------------------------- |
| `type`     | string  | Always `"updateLeverage"`                            |
| `asset`    | number  | Asset index to update leverage for                   |
| `isCross`  | boolean | `true` for cross margin, `false` for isolated margin |
| `leverage` | number  | New leverage value (e.g., 2 for 2x leverage)         |

## Margin Modes

### Cross Margin (`isCross: true`)

- Shares margin across all positions
- Unrealized PnL from other positions can prevent liquidation
- More capital efficient but higher risk of cascade liquidations

### Isolated Margin (`isCross: false`)

- Each position has dedicated margin
- Losses are limited to the position's margin
- Requires more capital but limits downside exposure

## Use Cases

### Risk Management Monitoring

Track leverage changes to understand trader risk appetite:

```python
def process_updateLeverage_action(action):
    asset = action.get('asset')
    leverage = action.get('leverage')
    margin_mode = 'cross' if action.get('isCross') else 'isolated'

    print(f"Leverage update: asset {asset} -> {leverage}x ({margin_mode})")
```

### Liquidation Risk Analysis

Monitor leverage increases that may indicate higher liquidation risk.

### Market Sentiment

Aggregate leverage changes can indicate market sentiment:

- Increasing leverage = More aggressive/bullish positioning
- Decreasing leverage = More conservative/risk-off

## Related Action Payloads

- [updateIsolatedMargin](https://www.dwellir.com/docs/hyperliquid/updateIsolatedMargin) - Isolated margin adjustments
- [userPortfolioMargin](https://www.dwellir.com/docs/hyperliquid/userPortfolioMargin) - Portfolio margin configuration
- [order](https://www.dwellir.com/docs/hyperliquid/order) - Trading orders affected by leverage settings

---

## usdClassTransfer payload - Margin Mode Transfers

# usdClassTransfer payload - Margin Mode Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `usdClassTransfer` payload records a USD-class asset transfer between perpetual and spot margin modes.

## Sample Data

```json
{
  "signature": {
    "r": "0xb6fb726ec034a9a8d5125cc9031012a58ba10f39c380a80566b56363a2a7cabf",
    "s": "0x6d4bc0977c2a7cb99c5ae1a5a9fd54fd219598661c12a36e344f52b3bdb6bc6b",
    "v": 28
  },
  "action": {
    "type": "usdClassTransfer",
    "signatureChainId": "0x66eee",
    "hyperliquidChain": "Mainnet",
    "amount": "55.00000001000001",
    "toPerp": true,
    "nonce": 1768146939642
  },
  "nonce": 1768146939642
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x5ac4b8e201a98b1d5c3e043326462d02016100c79caca9effe8d6434c0ad6507)

## Field Reference

### Action Fields

| Field              | Type    | Description                                               |
| ------------------ | ------- | --------------------------------------------------------- |
| `type`             | string  | Always `"usdClassTransfer"`                               |
| `signatureChainId` | string  | Chain ID for EIP-712 signing                              |
| `hyperliquidChain` | string  | Target chain: `"Mainnet"` or `"Testnet"`                  |
| `amount`           | string  | Amount to transfer (human-readable USD)                   |
| `toPerp`           | boolean | `true` to transfer to perp margin, `false` to spot margin |
| `nonce`            | number  | Transaction nonce                                         |

## Transfer Direction

| `toPerp` Value | Direction                 |
| -------------- | ------------------------- |
| `true`         | Spot margin → Perp margin |
| `false`        | Perp margin → Spot margin |

## Use Cases

### Capital Flow Analysis

Track how traders allocate between perp and spot:

```python
def process_usdClassTransfer_action(action):
    amount = action.get('amount')
    to_perp = action.get('toPerp')

    direction = 'spot → perp' if to_perp else 'perp → spot'
    print(f"Margin transfer: ${amount} ({direction})")
```

### Market Mode Preference

Monitor aggregate flows to understand market preferences between spot and perp trading.

### Arbitrage Detection

Large transfers may indicate arbitrage opportunities between markets.

## Related Action Payloads

- [usdSend](https://www.dwellir.com/docs/hyperliquid/usdSend) - USD transfers
- [spotSend](https://www.dwellir.com/docs/hyperliquid/spotSend) - Spot token transfers
- [subAccountTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountTransfer) - Sub-account transfers

---

## usdSend payload - USD Transfers

# usdSend payload - USD Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `usdSend` payload records an internal USD transfer between Hyperliquid addresses.

## Sample Data

```json
{
  "signature": {
    "r": "0x2bb37a8b0c893d0e4a2f0e28e2411aad8fd31baeccb4188fb7aa58b92478ba96",
    "s": "0x6b806e50eabbfa1d275a0afc9e932296df700bc9022af48ef7b87e806da9b538",
    "v": 27
  },
  "action": {
    "type": "usdSend",
    "signatureChainId": "0xa4b1",
    "hyperliquidChain": "Mainnet",
    "destination": "0x192c181edebbad21a90e3aeec3519d30528c6d60",
    "amount": "17.18",
    "time": 1768146943132
  },
  "nonce": 1768146943132
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x7c55ce705c37a4047dcf043326465e02013d0055f73ac2d6201e79c31b3b7def)

## Field Reference

### Action Fields

| Field              | Type   | Description                              |
| ------------------ | ------ | ---------------------------------------- |
| `type`             | string | Always `"usdSend"`                       |
| `signatureChainId` | string | Chain ID for EIP-712 signing             |
| `hyperliquidChain` | string | Target chain: `"Mainnet"` or `"Testnet"` |
| `destination`      | string | Recipient's address                      |
| `amount`           | string | Amount in USD                            |
| `time`             | number | Transaction timestamp                    |

## Use Cases

### Internal Transfer Tracking

Monitor USD movements between accounts:

```python
def process_usdSend_action(action):
    destination = action.get('destination')
    amount = action.get('amount')
    print(f"USD transfer: ${amount} to {destination[:10]}...")
```

## Related Action Payloads

- [spotSend](https://www.dwellir.com/docs/hyperliquid/spotSend) - Spot token transfers
- [usdClassTransfer](https://www.dwellir.com/docs/hyperliquid/usdClassTransfer) - Margin-mode transfers

---

## userAbstraction - HyperCore Info Endpoint

# userAbstraction - HyperCore Info Endpoint

Get the account abstraction mode for a user on Hyperliquid, indicating whether the account operates in unified, portfolio margin, or another mode.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `userAbstraction` endpoint is essential for:

- **Account Mode Detection** — Determine how a user's account is configured
- **Margin Logic** — Adapt margin calculations based on unified vs portfolio margin mode
- **UI Customization** — Display the correct interface based on account abstraction type
- **Trading Logic** — Adjust order placement and risk management based on account mode

## Request Parameters

- `type` (`string, required`): parameter: Must be `"userAbstraction"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userAbstraction",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response Returns a string indicating the account abstraction mode for the specified user. ```json "unifiedAccount" ``` ### Possible Values | Value | Description | |-------|-------------| | `unifiedAccount` | Unified account mode — perps and spot share a single margin pool | | `portfolioMargin` | Portfolio margin mode — margin calculated across the full portfolio | | `disabled` | Account abstraction is disabled | | `default` | Default account mode |

## Successful Response

```json
"unifiedAccount"
```

## Common Use Cases

### 1. Check Account Mode

Determine the account abstraction mode before executing trades:

```javascript
async function checkAccountMode(userAddress) {
  const mode = await getUserAbstraction(userAddress);

  console.log('=== Account Mode ===\n');
  console.log(`Mode: ${mode}`);

  return mode;
}

// Usage
const mode = await checkAccountMode('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

### 2. Adapt Trading Logic

Adjust trading behavior based on account mode:

```javascript
async function getTradeConfig(userAddress) {
  const mode = await getUserAbstraction(userAddress);

  const configs = {
    unifiedAccount: {
      marginShared: true,
      spotAndPerpsLinked: true,
      description: 'Perps and spot share a single margin pool'
    },
    portfolioMargin: {
      marginShared: true,
      spotAndPerpsLinked: true,
      description: 'Margin calculated across the full portfolio'
    },
    disabled: {
      marginShared: false,
      spotAndPerpsLinked: false,
      description: 'Standard isolated margin mode'
    },
    default: {
      marginShared: false,
      spotAndPerpsLinked: false,
      description: 'Default account configuration'
    }
  };

  return configs[mode] || configs['default'];
}

// Usage
const config = await getTradeConfig('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`Mode: ${config.description}`);
console.log(`Margin shared: ${config.marginShared}`);
```

### 3. Display Account Mode Badge

Show account mode in a dashboard:

```javascript
async function getAccountModeBadge(userAddress) {
  const mode = await getUserAbstraction(userAddress);

  const badges = {
    unifiedAccount: { label: 'Unified Account', color: 'green' },
    portfolioMargin: { label: 'Portfolio Margin', color: 'blue' },
    disabled: { label: 'Standard', color: 'gray' },
    default: { label: 'Default', color: 'gray' }
  };

  return badges[mode] || { label: mode, color: 'gray' };
}

// Usage
const badge = await getAccountModeBadge('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`Display badge: ${badge.label} (${badge.color})`);
```

## Best Practices

1. **Cache mode data** — Account mode changes infrequently, cache for 5-10 minutes
2. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
3. **Handle unknown modes** — Have fallback logic for unrecognized mode values
4. **Check before trading** — Query account mode before placing orders that depend on margin type
5. **Update on mode change** — Invalidate cached data when users switch account modes

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get perpetual account state
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot account balances
- [**portfolioState**](https://www.dwellir.com/docs/hyperliquid/portfolio-state) — Get perp state, spot balances, and account mode in one response
- [**userRole**](https://www.dwellir.com/docs/hyperliquid/user-role) — Get user role information
- [**subAccounts**](https://www.dwellir.com/docs/hyperliquid/sub-accounts) — Get sub-account details

***

*Check account abstraction modes with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## userFees - HyperCore Info Endpoint

# userFees - HyperCore Info Endpoint

Get fee rates, volume information, and referral discounts for a user on Hyperliquid.

The live response includes `dailyUserVlm`, `feeSchedule`, top-level fee fields such as `userCrossRate` and `userAddRate`, plus spot fee rates and active discount metadata.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `userFees` endpoint is essential for traders, trading platforms, and analytics tools who need to:

- **Calculate Trading Costs** — Estimate fees before placing orders
- **Volume Tracking** — Monitor daily trading volume
- **Fee Optimization** — Compare user's fees against standard schedule
- **Referral Programs** — Track referral discounts and benefits

## Request Parameters

- `type` (`string, required`): parameter: Must be `"userFees"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userFees",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `dailyUserVlm` (`array, required`): Array of daily trading volume objects (last 15 days)
- `feeSchedule` (`object, required`): Complete fee schedule with tiers and discounts
- `userCrossRate` (`string, required`): User's current cross margin fee rate
- `userAddRate` (`string, required`): User's current add liquidity fee rate
- `userSpotCrossRate` (`string, required`): User's current spot cross margin fee rate
- `userSpotAddRate` (`string, required`): User's current spot add liquidity fee rate
- `activeReferralDiscount` (`string, required`): Active referral discount (decimal, e.g., "0.04" = 4%)
- `trial` (`null | object, required`): Fee trial information if active
- `feeTrialEscrow` (`string, required`): Amount in escrow for fee trial
- `nextTrialAvailableTimestamp` (`null | integer, required`): Timestamp when next trial becomes available
- `stakingLink` (`null | string, required`): Staking link if applicable
- `activeStakingDiscount` (`object, required`): Current staking discount tier

## Successful Response

```json
{
  "dailyUserVlm": [
    {
      "date": "2026-02-07",
      "userCross": "0.0",
      "userAdd": "0.0",
      "exchange": "6761946801.4399995804"
    },
    {
      "date": "2026-02-08",
      "userCross": "0.0",
      "userAdd": "0.0",
      "exchange": "3963888811.4499998093"
    },
    {
      "date": "2026-02-09",
      "userCross": "0.0",
      "userAdd": "0.0",
      "exchange": "2538522069.9000000954"
    }
  ],
  "feeSchedule": {
    "cross": "0.00045",
    "add": "0.00015",
    "spotCross": "0.0007",
    "spotAdd": "0.0004",
    "tiers": {
      "vip": [
        {
          "ntlCutoff": "5000000.0",
          "cross": "0.0004",
          "add": "0.00012",
          "spotCross": "0.0006",
          "spotAdd": "0.0003"
        }
      ],
      "mm": [
        {
          "makerFractionCutoff": "0.005",
          "add": "-0.00001"
        }
      ]
    },
    "referralDiscount": "0.04",
    "stakingDiscountTiers": [
      {
        "bpsOfMaxSupply": "0.0",
        "discount": "0.0"
      },
      {
        "bpsOfMaxSupply": "0.0001",
        "discount": "0.05"
      }
    ]
  },
  "userCrossRate": "0.00045",
  "userAddRate": "0.00015",
  "userSpotCrossRate": "0.0007",
  "userSpotAddRate": "0.0004",
  "activeReferralDiscount": "0.04",
  "trial": null,
  "feeTrialEscrow": "0.0",
  "nextTrialAvailableTimestamp": null,
  "stakingLink": null,
  "activeStakingDiscount": {
    "bpsOfMaxSupply": "0.0",
    "discount": "0.0"
  }
}
```

## Common Use Cases

### 1. Calculate Trading Costs

Estimate fees for a trade:

```javascript
async function calculateTradingFee(userAddress, orderValue, isMaker = false) {
  const fees = await getUserFees(userAddress);

  // Use the live top-level fee fields from the response
  const feeRate = isMaker
    ? parseFloat(fees.userAddRate)
    : parseFloat(fees.userCrossRate);

  // Apply the active referral discount if available
  const discount = parseFloat(fees.activeReferralDiscount ?? '0');
  const effectiveRate = feeRate * (1 - discount);

  const feeAmount = orderValue * effectiveRate;

  return {
    orderValue: orderValue,
    feeRate: feeRate,
    discount: discount,
    effectiveRate: effectiveRate,
    feeAmount: feeAmount,
    feeBps: effectiveRate * 10000
  };
}

// Usage
const tradeFee = await calculateTradingFee(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  10000, // $10,000 order
  true   // maker order
);

console.log(`Order Value: $${tradeFee.orderValue}`);
console.log(`Fee Rate: ${tradeFee.feeBps.toFixed(2)} bps`);
console.log(`Estimated Fee: $${tradeFee.feeAmount.toFixed(2)}`);
```

### 2. Compare Against Standard Fees

Compare user's fees to standard rates:

```javascript
async function compareFeeRates(userAddress, standardRate = 0.0005) {
  const fees = await getUserFees(userAddress);
  const userRate = parseFloat(fees.userCrossRate);

  const savingsBps = (standardRate - userRate) * 10000;
  const savingsPercent = ((standardRate - userRate) / standardRate) * 100;

  return {
    userRate: userRate,
    standardRate: standardRate,
    savingsBps: savingsBps,
    savingsPercent: savingsPercent,
    hasBetterRate: userRate < standardRate
  };
}

// Usage
const comparison = await compareFeeRates(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  0.0005 // 5 bps standard
);

if (comparison.hasBetterRate) {
  console.log(`You save ${comparison.savingsBps.toFixed(2)} bps (${comparison.savingsPercent.toFixed(1)}%)`);
}
```

### 3. Estimate Monthly Fee Savings

Calculate potential savings with referral discount:

```javascript
async function estimateMonthlySavings(userAddress, monthlyVolume) {
  const fees = await getUserFees(userAddress);

  const baseRate = parseFloat(fees.userCrossRate);
  const discount = parseFloat(fees.activeReferralDiscount ?? '0');

  const baseFees = monthlyVolume * baseRate;
  const discountedFees = baseFees * (1 - discount);
  const savings = baseFees - discountedFees;

  return {
    monthlyVolume: monthlyVolume,
    baseRate: baseRate,
    discount: discount,
    baseFees: baseFees,
    discountedFees: discountedFees,
    savings: savings,
    savingsPercent: discount * 100
  };
}

// Usage
const savings = await estimateMonthlySavings(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  1000000 // $1M monthly volume
);

console.log(`Monthly Volume: $${savings.monthlyVolume.toLocaleString()}`);
console.log(`Base Fees: $${savings.baseFees.toFixed(2)}`);
console.log(`With Discount: $${savings.discountedFees.toFixed(2)}`);
console.log(`Monthly Savings: $${savings.savings.toFixed(2)}`);
```

### 4. Fee Tier Analyzer

Analyze user's fee tier and potential improvements:

```javascript
async function analyzeFeePosition(userAddress) {
  const fees = await getUserFees(userAddress);

  const crossRate = parseFloat(fees.userCrossRate);
  const addRate = parseFloat(fees.userAddRate);
  const discount = parseFloat(fees.activeReferralDiscount ?? '0');

  // Example tier thresholds (adjust based on actual schedule)
  const tiers = [
    { name: 'Standard', rate: 0.0005, minVolume: 0 },
    { name: 'Tier 1', rate: 0.0004, minVolume: 100000 },
    { name: 'Tier 2', rate: 0.0003, minVolume: 500000 },
    { name: 'Tier 3', rate: 0.0002, minVolume: 2000000 },
  ];

  const currentTier = tiers.findLast(t => t.rate >= crossRate) || tiers[0];
  const nextTier = tiers[tiers.indexOf(currentTier) + 1];

  console.log('=== Fee Analysis ===\n');
  console.log(`Current Cross Rate: ${(crossRate * 10000).toFixed(2)} bps`);
  console.log(`Current Add Rate: ${(addRate * 10000).toFixed(2)} bps`);
  console.log(`Estimated Tier: ${currentTier.name}`);

  if (discount > 0) {
    console.log(`Referral Discount: ${(discount * 100).toFixed(1)}%`);
  }

  if (nextTier) {
    const improvement = ((crossRate - nextTier.rate) / crossRate) * 100;
    console.log(`\nNext tier saves ${improvement.toFixed(1)}% on fees`);
    console.log(`Requires ~$${nextTier.minVolume.toLocaleString()} monthly volume`);
  }
}
```

### 5. Fee Comparison Tool

Compare fees across different order types:

```javascript
async function compareFeeTypes(userAddress, orderValue) {
  const fees = await getUserFees(userAddress);

  const makerRate = parseFloat(fees.userAddRate);
  const takerRate = parseFloat(fees.userCrossRate);
  const discount = parseFloat(fees.activeReferralDiscount ?? '0');

  const makerFee = orderValue * makerRate * (1 - discount);
  const takerFee = orderValue * takerRate * (1 - discount);

  console.log(`Order Value: $${orderValue.toLocaleString()}\n`);

  console.log('Maker Order (limit):');
  console.log(`  Rate: ${(makerRate * 10000).toFixed(2)} bps`);
  console.log(`  Fee: $${makerFee.toFixed(2)}`);

  console.log('\nTaker Order (market):');
  console.log(`  Rate: ${(takerRate * 10000).toFixed(2)} bps`);
  console.log(`  Fee: $${takerFee.toFixed(2)}`);

  console.log(`\nSavings with maker: $${(takerFee - makerFee).toFixed(2)}`);
}
```

## Best Practices

1. **Cache fee data** — Fee rates change infrequently, cache for several minutes
2. **Always use effective rate** — Apply referral discount when calculating costs
3. **Display fees clearly** — Show both basis points and dollar amounts
4. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
5. **Consider order type** — Use correct rate for maker vs taker orders

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state and trading volume
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — See orders that will incur fees
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot trading balances

***

*Access real-time Hyperliquid fee information with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## userRateLimit - HyperCore Info Endpoint

# userRateLimit - HyperCore Info Endpoint

Get rate limit information for a user on Hyperliquid, including cumulative volume and request-cap usage.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `userRateLimit` endpoint is essential for:

- **Usage Monitoring** — Track API usage against rate limits
- **Optimization** — Identify when to throttle requests
- **Compliance** — Ensure requests stay within allowed limits
- **Planning** — Understand user-specific rate limit allocations

## Request Parameters

- `type` (`string, required`): parameter: Must be `"userRateLimit"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userRateLimit",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `limit` (`integer, required`): Maximum number of requests allowed
- `remaining` (`integer, required`): Number of requests remaining in current period
- `reset` (`integer, required`): Unix timestamp (milliseconds) when rate limit resets

## Successful Response

```json
{
  "limit": 100,
  "remaining": 95,
  "reset": 1704067200000
}
```

## Common Use Cases

### 1. Check Rate Limit Status

Monitor current rate limit status:

```javascript
async function checkRateLimitStatus(userAddress) {
  const rateLimit = await getUserRateLimit(userAddress);

  const percentUsed = (rateLimit.nRequestsUsed / rateLimit.nRequestsCap) * 100;

  console.log('=== Rate Limit Status ===\n');
  console.log(`Cumulative volume: ${rateLimit.cumVlm}`);
  console.log(`Requests used: ${rateLimit.nRequestsUsed}/${rateLimit.nRequestsCap}`);
  console.log(`Used: ${percentUsed.toFixed(1)}%`);

  if (rateLimit.nRequestsSurplus > 0) {
    console.warn('WARNING: Approaching rate limit!');
  }
}
```

### 2. Implement Smart Throttling

Automatically throttle requests based on remaining capacity:

```javascript
class RateLimitedClient {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.lastCheck = null;
  }

  async shouldThrottle() {
    const rateLimit = await getUserRateLimit(this.userAddress);
    this.lastCheck = Date.now();

    // Throttle if usage is approaching the cap
    const usedPercent = (rateLimit.nRequestsUsed / rateLimit.nRequestsCap) * 100;
    return usedPercent > 80;
  }

  async makeRequest(requestFn) {
    if (await this.shouldThrottle()) {
      console.log('Throttling: rate-cap usage is high');
      await new Promise(r => setTimeout(r, 1000));
    }

    return await requestFn();
  }
}

// Usage
const client = new RateLimitedClient('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
const result = await client.makeRequest(() => someApiCall());
```

### 3. Build Rate Limit Monitor

Create a monitoring system:

```javascript
async function monitorRateLimit(userAddress, alertThreshold = 10) {
  const rateLimit = await getUserRateLimit(userAddress);

  const status = {
    cumulativeVolume: rateLimit.cumVlm,
    requestsUsed: rateLimit.nRequestsUsed,
    requestsCap: rateLimit.nRequestsCap,
    requestsSurplus: rateLimit.nRequestsSurplus,
    percentUsed: (rateLimit.nRequestsUsed / rateLimit.nRequestsCap) * 100
  };

  if (status.requestsSurplus > 0) {
    console.error(`ALERT: Request cap exceeded by ${status.requestsSurplus}`);
  }

  return status;
}

// Usage
const status = await monitorRateLimit('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log('Rate limit status:', status);
```

### 4. Calculate Optimal Request Rate

Calculate safe request rate:

```javascript
async function calculateOptimalRate(userAddress) {
  const rateLimit = await getUserRateLimit(userAddress);

  const safeRPS = Math.max(1, Math.floor(rateLimit.nRequestsCap / 60));

  return {
    safeRPS: safeRPS,
    delayBetweenRequests: 1000 / safeRPS
  };
}

// Usage
const optimal = await calculateOptimalRate('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`Safe request rate: ${optimal.safeRPS.toFixed(2)} req/s`);
console.log(`Delay between requests: ${optimal.delayBetweenRequests.toFixed(0)}ms`);
```

### 5. Rate Limit Dashboard

Create a comprehensive rate limit dashboard:

```javascript
async function getRateLimitDashboard(userAddress) {
  try {
    const rateLimit = await getUserRateLimit(userAddress);

    const percentUsed = (rateLimit.nRequestsUsed / rateLimit.nRequestsCap) * 100;

    return {
      status: 'success',
      metrics: {
        cumulativeVolume: rateLimit.cumVlm,
        used: rateLimit.nRequestsUsed,
        cap: rateLimit.nRequestsCap,
        surplus: rateLimit.nRequestsSurplus,
        percentUsed: percentUsed.toFixed(1) + '%'
      },
      health: percentUsed < 80 ? 'healthy' : percentUsed < 95 ? 'warning' : 'critical'
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message
    };
  }
}
```

## Best Practices

1. **Check regularly** — Monitor rate limits before making bulk requests
2. **Respect limits** — Implement throttling when approaching limits
3. **Cache strategically** — Cache rate limit data for 10-30 seconds
4. **Plan ahead** — Check limits before starting long-running operations
5. **Implement backoff** — Use exponential backoff when limits are reached

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get user fee information
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get user open orders

***

*Monitor and optimize your Hyperliquid API usage with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## userRole - HyperCore Info Endpoint

# userRole - HyperCore Info Endpoint

Get role information for a user on Hyperliquid, including permissions, access levels, and account capabilities.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `userRole` endpoint is essential for:

- **Permission Checking** — Verify user access levels and capabilities
- **Access Control** — Implement role-based access in applications
- **Feature Gating** — Enable/disable features based on user role
- **Account Management** — Understand account type and permissions

## Request Parameters

- `type` (`string, required`): parameter: Must be `"userRole"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userRole",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `role` (`string, required`): User's role on the platform (e.g., "standard", "vip", "market_maker")

## Successful Response

```json
{
  "role": "standard"
}
```

## Common Use Cases

### 1. Check User Permissions

Verify user role for access control:

```javascript
async function checkUserPermissions(userAddress) {
  const roleData = await getUserRole(userAddress);

  console.log('=== User Permissions ===\n');
  console.log(`Role: ${roleData.role}`);

  return roleData.role;
}

// Usage
const role = await checkUserPermissions('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

### 2. Role-Based Feature Access

Implement role-based feature gating:

```javascript
async function canAccessFeature(userAddress, featureName) {
  const roleData = await getUserRole(userAddress);

  // Define feature access by role
  const featureAccess = {
    standard: ['basic_trading', 'view_data'],
    vip: ['basic_trading', 'view_data', 'advanced_analytics', 'priority_support'],
    market_maker: ['basic_trading', 'view_data', 'advanced_analytics', 'market_making', 'api_access']
  };

  const userFeatures = featureAccess[roleData.role] || [];
  const hasAccess = userFeatures.includes(featureName);

  console.log(`Feature "${featureName}": ${hasAccess ? 'Granted' : 'Denied'}`);
  return hasAccess;
}

// Usage
const canUseAdvancedAnalytics = await canAccessFeature(
  '0x63E8c7C149556D5f34F833419A287bb9Ef81487f',
  'advanced_analytics'
);
```

### 3. Display Role Badge

Show user role in UI:

```javascript
async function getUserRoleBadge(userAddress) {
  const roleData = await getUserRole(userAddress);

  const badges = {
    standard: { label: 'Standard', color: 'gray' },
    vip: { label: 'VIP', color: 'gold' },
    market_maker: { label: 'Market Maker', color: 'blue' }
  };

  return badges[roleData.role] || { label: 'User', color: 'gray' };
}

// Usage
const badge = await getUserRoleBadge('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`Display badge: ${badge.label} (${badge.color})`);
```

### 4. Build Access Control System

Create comprehensive access control:

```javascript
class AccessControl {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.role = null;
  }

  async initialize() {
    const roleData = await getUserRole(this.userAddress);
    this.role = roleData.role;
    return this.role;
  }

  hasPermission(permission) {
    const permissions = {
      standard: ['read', 'basic_trade'],
      vip: ['read', 'basic_trade', 'advanced_trade', 'analytics'],
      market_maker: ['read', 'basic_trade', 'advanced_trade', 'analytics', 'market_make', 'api']
    };

    const userPermissions = permissions[this.role] || [];
    return userPermissions.includes(permission);
  }

  getPermissions() {
    const permissions = {
      standard: ['read', 'basic_trade'],
      vip: ['read', 'basic_trade', 'advanced_trade', 'analytics'],
      market_maker: ['read', 'basic_trade', 'advanced_trade', 'analytics', 'market_make', 'api']
    };

    return permissions[this.role] || [];
  }
}

// Usage
const acl = new AccessControl('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
await acl.initialize();

if (acl.hasPermission('advanced_trade')) {
  console.log('User can access advanced trading');
}
```

### 5. Role-Based Dashboard

Customize dashboard based on user role:

```javascript
async function buildRoleBasedDashboard(userAddress) {
  const roleData = await getUserRole(userAddress);

  const dashboardConfig = {
    standard: {
      widgets: ['account_summary', 'basic_charts', 'order_book'],
      features: ['basic_trading']
    },
    vip: {
      widgets: ['account_summary', 'advanced_charts', 'order_book', 'analytics'],
      features: ['basic_trading', 'advanced_trading', 'analytics']
    },
    market_maker: {
      widgets: ['account_summary', 'advanced_charts', 'order_book', 'analytics', 'api_stats'],
      features: ['basic_trading', 'advanced_trading', 'analytics', 'market_making', 'api_access']
    }
  };

  const config = dashboardConfig[roleData.role] || dashboardConfig.standard;

  return {
    role: roleData.role,
    dashboard: config,
    timestamp: new Date().toISOString()
  };
}

// Usage
const dashboard = await buildRoleBasedDashboard('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log('Dashboard configuration:', dashboard);
```

## Best Practices

1. **Cache role data** — Role changes infrequently, cache for 5-10 minutes
2. **Validate addresses** — Ensure user addresses are valid Ethereum addresses
3. **Default to least privilege** — Use most restrictive role as default
4. **Handle unknown roles** — Have fallback for unrecognized roles
5. **Implement feature flags** — Combine with feature flags for flexible access control

## Performance Tips

### Cached Role Checker

```javascript
class CachedRoleChecker {
  constructor(cacheDurationMs = 300000) {
    this.cache = new Map();
    this.cacheDurationMs = cacheDurationMs; // 5 minutes
  }

  async getRole(userAddress) {
    const cached = this.cache.get(userAddress);
    const now = Date.now();

    if (cached && (now - cached.timestamp) < this.cacheDurationMs) {
      return cached.role;
    }

    const roleData = await getUserRole(userAddress);
    this.cache.set(userAddress, {
      role: roleData.role,
      timestamp: now
    });

    return roleData.role;
  }

  invalidate(userAddress) {
    this.cache.delete(userAddress);
  }

  clearAll() {
    this.cache.clear();
  }
}

// Usage
const roleChecker = new CachedRoleChecker();
const role = await roleChecker.getRole('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

## Related Endpoints

- [**extraAgents**](https://www.dwellir.com/docs/hyperliquid/extra-agents) — Get agent information
- [**subAccounts**](https://www.dwellir.com/docs/hyperliquid/sub-accounts) — Get sub-account details
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get account state
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get fee information (may vary by role)

***

*Implement role-based access control with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## userToMultiSigSigners - HyperCore Info Endpoint

# userToMultiSigSigners - HyperCore Info Endpoint

Get the signer set of a HyperCore multi-sig account: the addresses authorized to sign for it and how many of them a valid action needs.

A multi-sig user is a HyperCore account controlled by several private keys. The live response is an object with `authorizedUsers` and `threshold`. A normal (single-key) account returns `null`.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

Use `userToMultiSigSigners` for:

- **Account classification**: Tell a multi-sig account apart from a normal one before building a signing flow
- **Signer verification**: Check that a key you hold is in the authorized set
- **Quorum planning**: Read `threshold` to know how many signatures an action needs
- **Security auditing**: Detect signer or threshold changes over time

## Request Parameters

- `type` (`string, required`): parameter: Must be `"userToMultiSigSigners"`
- `user` (`string, required`): parameter: Address of the account to inspect

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userToMultiSigSigners",
  "user": "0x94757f8dcb4bf73b850195660e959d1105cfedd5"
}'
```

## Response Fields

- `authorizedUsers` (`array, required`): Addresses authorized to sign for the multi-sig account
- `threshold` (`integer, required`): Number of authorized signatures an action needs

## Successful Response

```json
{
  "authorizedUsers": [
    "0x1b19c451ba9afba29865cd4202523629624bfecf",
    "0x2c96305c90215fbe76a100a69ec00099eb07a8fd",
    "0x52997cfadc2fb563285dd308b7ef319db79c27a9",
    "0xa928ab80a3a3f286a9a8fd998c895298b2bc3a3e",
    "0xae8e318a2c606928a8539f06f9f42f049255f5ee",
    "0xeee3abbe9fd8162bede5401bfa7f2c98216cbbe4"
  ],
  "threshold": 4
}
```

## Common Use Cases

### 1. Classify an Account

```javascript
async function isMultiSig(userAddress) {
  const signers = await getMultiSigSigners(userAddress);
  return signers !== null;
}

// Usage
console.log(await isMultiSig('0x94757f8dcb4bf73b850195660e959d1105cfedd5')); // true
```

### 2. Verify a Signer

```javascript
async function canSign(userAddress, signerAddress) {
  const signers = await getMultiSigSigners(userAddress);
  if (signers === null) {
    return false;
  }
  const wanted = signerAddress.toLowerCase();
  return signers.authorizedUsers.some((a) => a.toLowerCase() === wanted);
}
```

### 3. Watch for Signer Changes

```javascript
class MultiSigMonitor {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.last = null;
  }

  async check() {
    const current = await getMultiSigSigners(this.userAddress);
    const key = JSON.stringify(current);
    if (this.last !== null && key !== this.last) {
      console.log('Signer set or threshold changed:', current);
    }
    this.last = key;
    return current;
  }
}

// Usage
const monitor = new MultiSigMonitor('0x94757f8dcb4bf73b850195660e959d1105cfedd5');
setInterval(() => monitor.check(), 60000);
```

## Best Practices

1. **Handle `null`**: A normal account returns `null`, not an empty object
2. **Compare addresses case-insensitively**: Signer addresses are returned lowercase
3. **Cache briefly**: Signer sets change rarely; a cache of a few minutes is safe
4. **Combine with `userRole`**: Use [userRole](https://www.dwellir.com/docs/hyperliquid/user-role) to learn whether the account is a user, vault, or sub-account

## Related Endpoints

- [**userRole**](https://www.dwellir.com/docs/hyperliquid/user-role): Get user role information
- [**extraAgents**](https://www.dwellir.com/docs/hyperliquid/extra-agents): Get extra agent information
- [**subAccounts**](https://www.dwellir.com/docs/hyperliquid/sub-accounts): Get sub-account information
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state): Get account state

***

*Inspect multi-sig accounts with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## userVaultEquities - HyperCore Info Endpoint

# userVaultEquities - HyperCore Info Endpoint

Get user's equity positions across all vaults, including share balances, current value, unrealized gains, and allocation details.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `userVaultEquities` endpoint is essential for portfolio trackers, wealth managers, and investors who need to:

- **Track Vault Investments** — Monitor all vault positions in one place
- **Calculate Portfolio Value** — Get real-time value of vault holdings
- **Analyze Performance** — Track unrealized gains/losses across vaults
- **Portfolio Management** — View vault allocation and diversification

## Request Parameters

- `type` (`string, required`): parameter: Must be `"userVaultEquities"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "userVaultEquities",
  "user": "0x66e7293b07744b2d92384d33a0f86b9c333d8597"
}'
```

## Response Fields

- `vaultAddress` (`string, required`): Ethereum address of the vault contract
- `equity` (`string, required`): User's current equity value in the vault (USD)
- `lockedUntilTimestamp` (`integer, required`): Unix timestamp (milliseconds) when vault funds unlock

## Successful Response

```json
[
  {
    "vaultAddress": "0x115849ce84370f25cadcf0d348510d73837e1aa5",
    "equity": "9773.685144",
    "lockedUntilTimestamp": 1770368683304
  }
]
```

## Common Use Cases

### 1. Calculate Total Vault Portfolio Value

Get comprehensive portfolio metrics:

```javascript
async function getVaultPortfolioMetrics(userAddress) {
  const equities = await getUserVaultEquities(userAddress);

  if (equities.length === 0) {
    return { message: 'No vault positions found' };
  }

  const totalCurrentValue = equities.reduce((sum, e) =>
    sum + parseFloat(e.currentValue), 0
  );

  const totalDeposited = equities.reduce((sum, e) =>
    sum + parseFloat(e.netDeposits), 0
  );

  const totalPnl = equities.reduce((sum, e) =>
    sum + parseFloat(e.unrealizedPnl), 0
  );

  const weightedReturn = equities.reduce((sum, e) => {
    const weight = parseFloat(e.currentValue) / totalCurrentValue;
    return sum + (parseFloat(e.pnlPercent) * weight);
  }, 0);

  return {
    totalPositions: equities.length,
    totalValue: totalCurrentValue.toFixed(2),
    totalDeposited: totalDeposited.toFixed(2),
    totalPnl: totalPnl.toFixed(2),
    totalReturnPercent: ((totalPnl / totalDeposited) * 100).toFixed(2),
    weightedReturnPercent: weightedReturn.toFixed(2),
    largestPosition: equities.reduce((max, e) =>
      parseFloat(e.currentValue) > parseFloat(max.currentValue) ? e : max
    )
  };
}

// Usage
const metrics = await getVaultPortfolioMetrics('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log('Portfolio Metrics:', metrics);
console.log(`Largest position: ${metrics.largestPosition.vaultName}`);
```

### 2. Check Withdrawal Availability

Determine which positions can be withdrawn:

```javascript
async function checkWithdrawalAvailability(userAddress) {
  const equities = await getUserVaultEquities(userAddress);
  const now = Date.now();

  const available = [];
  const locked = [];

  equities.forEach(equity => {
    const position = {
      vaultName: equity.vaultName,
      value: parseFloat(equity.currentValue),
      shares: parseFloat(equity.shares),
      lockupExpiry: equity.lockupExpiry
    };

    if (equity.lockupExpiry <= now) {
      position.status = 'Available';
      available.push(position);
    } else {
      const daysRemaining = Math.ceil((equity.lockupExpiry - now) / (1000 * 60 * 60 * 24));
      position.status = 'Locked';
      position.daysRemaining = daysRemaining;
      locked.push(position);
    }
  });

  const availableValue = available.reduce((sum, p) => sum + p.value, 0);
  const lockedValue = locked.reduce((sum, p) => sum + p.value, 0);

  return {
    available: available,
    locked: locked,
    availableValue: availableValue.toFixed(2),
    lockedValue: lockedValue.toFixed(2),
    totalValue: (availableValue + lockedValue).toFixed(2)
  };
}

// Usage
const withdrawal = await checkWithdrawalAvailability('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`\nWithdrawal Status:`);
console.log(`Available: $${withdrawal.availableValue}`);
console.log(`Locked: $${withdrawal.lockedValue}`);

console.log(`\nAvailable Positions (${withdrawal.available.length}):`);
withdrawal.available.forEach(p => {
  console.log(`  ${p.vaultName}: $${p.value.toLocaleString()}`);
});

console.log(`\nLocked Positions (${withdrawal.locked.length}):`);
withdrawal.locked.forEach(p => {
  console.log(`  ${p.vaultName}: $${p.value.toLocaleString()} (${p.daysRemaining} days)`);
});
```

### 3. Analyze Vault Allocation

View portfolio diversification across vaults:

```javascript
async function analyzeVaultAllocation(userAddress) {
  const equities = await getUserVaultEquities(userAddress);

  const totalValue = equities.reduce((sum, e) =>
    sum + parseFloat(e.currentValue), 0
  );

  const allocation = equities.map(e => {
    const value = parseFloat(e.currentValue);
    const percentage = (value / totalValue) * 100;

    return {
      vaultName: e.vaultName,
      value: value,
      percentage: percentage.toFixed(2),
      shares: parseFloat(e.shares),
      pnl: parseFloat(e.unrealizedPnl),
      pnlPercent: parseFloat(e.pnlPercent)
    };
  }).sort((a, b) => b.value - a.value);

  // Check concentration risk
  const top3Concentration = allocation.slice(0, 3).reduce((sum, a) =>
    sum + parseFloat(a.percentage), 0
  );

  return {
    allocation: allocation,
    totalValue: totalValue.toFixed(2),
    positions: allocation.length,
    top3Concentration: top3Concentration.toFixed(2),
    diversified: top3Concentration < 75
  };
}

// Usage
const analysis = await analyzeVaultAllocation('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`\n=== Portfolio Allocation ===`);
console.log(`Total Value: $${parseFloat(analysis.totalValue).toLocaleString()}`);
console.log(`Positions: ${analysis.positions}`);
console.log(`Top 3 Concentration: ${analysis.top3Concentration}%`);
console.log(`Diversified: ${analysis.diversified ? 'Yes' : 'No (concentrated)'}`);

console.log(`\n=== Allocation by Vault ===`);
analysis.allocation.forEach((a, i) => {
  console.log(`${i + 1}. ${a.vaultName}: ${a.percentage}% ($${a.value.toLocaleString()})`);
  console.log(`   PnL: ${a.pnlPercent > 0 ? '+' : ''}${a.pnlPercent}%`);
});
```

### 4. Track Performance Over Time

Monitor vault performance metrics:

```javascript
async function trackVaultPerformance(userAddress) {
  const equities = await getUserVaultEquities(userAddress);

  const performance = equities.map(e => {
    const currentValue = parseFloat(e.currentValue);
    const depositValue = parseFloat(e.netDeposits);
    const pnl = parseFloat(e.unrealizedPnl);
    const pnlPercent = parseFloat(e.pnlPercent);

    // Calculate holding period
    const depositDate = new Date(e.depositTimestamp);
    const now = new Date();
    const daysHeld = Math.floor((now - depositDate) / (1000 * 60 * 60 * 24));

    // Annualized return
    const annualizedReturn = daysHeld > 0
      ? (pnlPercent / daysHeld) * 365
      : 0;

    return {
      vaultName: e.vaultName,
      currentValue: currentValue,
      depositValue: depositValue,
      pnl: pnl,
      returnPercent: pnlPercent,
      daysHeld: daysHeld,
      annualizedReturn: annualizedReturn.toFixed(2),
      dailyReturn: daysHeld > 0 ? (pnlPercent / daysHeld).toFixed(3) : '0.000'
    };
  }).sort((a, b) => parseFloat(b.annualizedReturn) - parseFloat(a.annualizedReturn));

  return performance;
}

// Usage
const performance = await trackVaultPerformance('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`\n=== Vault Performance ===`);
performance.forEach((p, i) => {
  console.log(`\n${i + 1}. ${p.vaultName}`);
  console.log(`   Value: $${p.currentValue.toLocaleString()}`);
  console.log(`   Return: ${p.returnPercent > 0 ? '+' : ''}${p.returnPercent}%`);
  console.log(`   Days Held: ${p.daysHeld}`);
  console.log(`   Annualized: ${p.annualizedReturn}%`);
  console.log(`   Daily Avg: ${p.dailyReturn}%`);
});
```

### 5. Identify Best and Worst Performers

Analyze which vaults are performing well:

```javascript
async function identifyPerformers(userAddress) {
  const equities = await getUserVaultEquities(userAddress);

  // Sort by PnL percentage
  const sorted = [...equities].sort((a, b) =>
    parseFloat(b.pnlPercent) - parseFloat(a.pnlPercent)
  );

  const bestPerformers = sorted.slice(0, 3).map(e => ({
    vaultName: e.vaultName,
    pnl: parseFloat(e.unrealizedPnl),
    pnlPercent: parseFloat(e.pnlPercent),
    value: parseFloat(e.currentValue)
  }));

  const worstPerformers = sorted.slice(-3).reverse().map(e => ({
    vaultName: e.vaultName,
    pnl: parseFloat(e.unrealizedPnl),
    pnlPercent: parseFloat(e.pnlPercent),
    value: parseFloat(e.currentValue)
  }));

  // Calculate averages
  const avgPnlPercent = equities.reduce((sum, e) =>
    sum + parseFloat(e.pnlPercent), 0
  ) / equities.length;

  return {
    bestPerformers: bestPerformers,
    worstPerformers: worstPerformers,
    avgReturn: avgPnlPercent.toFixed(2),
    spread: (parseFloat(sorted[0].pnlPercent) - parseFloat(sorted[sorted.length - 1].pnlPercent)).toFixed(2)
  };
}

// Usage
const performers = await identifyPerformers('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');

console.log(`\n=== Best Performers ===`);
performers.bestPerformers.forEach((p, i) => {
  console.log(`${i + 1}. ${p.vaultName}: +${p.pnlPercent}% ($${p.pnl.toLocaleString()})`);
});

console.log(`\n=== Worst Performers ===`);
performers.worstPerformers.forEach((p, i) => {
  console.log(`${i + 1}. ${p.vaultName}: ${p.pnlPercent}% ($${p.pnl.toLocaleString()})`);
});

console.log(`\nPortfolio Statistics:`);
console.log(`Average Return: ${performers.avgReturn}%`);
console.log(`Performance Spread: ${performers.spread}%`);
```

## Best Practices

1. **Poll responsibly** — Update vault positions every 30-60 seconds for dashboards
2. **Handle empty results** — Users may have no vault positions
3. **Check lockup periods** — Verify withdrawal availability before transactions
4. **Track allocation** — Monitor portfolio concentration and diversification
5. **Calculate returns properly** — Account for deposits/withdrawals over time

## Related Endpoints

- [**leadingVaults**](https://www.dwellir.com/docs/hyperliquid/leading-vaults) — Discover top-performing vaults
- [**vaultSummaries**](https://www.dwellir.com/docs/hyperliquid/vault-summaries) — Get comprehensive vault information
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get user's perpetual account state
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot trading balances

***

*Track your Hyperliquid vault investments with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## userDexAbstraction payload - DEX Abstraction Settings

# userDexAbstraction payload - DEX Abstraction Settings

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `userDexAbstraction` payload records a change to a user's DEX abstraction settings.

## Sample Data

```json
{
  "signature": {
    "r": "0x9b539b38d3dd3c7d39d5da040409401ec0e6ac6aef40715b8d3cd60b0c2c48f6",
    "s": "0x3d22fd88f17177a8ebcc0bf40d3a996fea3a8f188ba0226a0f4d7776462a5ee0",
    "v": 28
  },
  "action": {
    "type": "userDexAbstraction",
    "signatureChainId": "0x2105",
    "hyperliquidChain": "Mainnet",
    "user": "0xb20088b36418bd7a3c845614c59aa9cebbec72de",
    "enabled": true,
    "nonce": 1768146986170
  },
  "nonce": 1768146986170
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x876d569faeaa634b88e70433264852020138008549ad821d2b3601f26dae3d36)

## Field Reference

### Action Fields

| Field     | Type    | Description                   |
| --------- | ------- | ----------------------------- |
| `type`    | string  | Always `"userDexAbstraction"` |
| `enabled` | boolean | DEX abstraction enabled       |

## Use Cases

### DEX Settings Tracking

Monitor DEX abstraction configuration:

```python
def process_userDexAbstraction_action(action):
    enabled = action.get('enabled')
    status = 'enabled' if enabled else 'disabled'
    print(f"DEX abstraction {status}")
```

## Related Action Payloads

- [agentEnableDexAbstraction](https://www.dwellir.com/docs/hyperliquid/agentEnableDexAbstraction) - Agent DEX settings
- [approveAgent](https://www.dwellir.com/docs/hyperliquid/approveAgent) - Agent authorization

---

## userPortfolioMargin payload - Portfolio Margin

# userPortfolioMargin payload - Portfolio Margin

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `userPortfolioMargin` payload records a change to an account's portfolio-margin configuration.

## Sample Data

```json
{
  "signature": {
    "r": "0x7e5f71ded930d4524d19dc7d6f04b2cb268355ee3a71465365017d12fccac779",
    "s": "0x16414434babfd4079bdedffd4c78644f66d95bee4287e4a375208b5ffe8893ea",
    "v": 27
  },
  "action": {
    "type": "userPortfolioMargin",
    "signatureChainId": "0xa4b1",
    "hyperliquidChain": "Mainnet",
    "user": "0xb714f435b61a228aa82d28fd4d975b041a88f85d",
    "enabled": true,
    "nonce": 1768147316503
  },
  "nonce": 1768147316503
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x79b10d620b87fc577b2a043326594b0201990047a68b1b291d79b8b4ca8bd642)

## Field Reference

### Action Fields

| Field              | Type    | Description                          |
| ------------------ | ------- | ------------------------------------ |
| `type`             | string  | Always `"userPortfolioMargin"`       |
| `signatureChainId` | string  | Chain ID for signing                 |
| `hyperliquidChain` | string  | Target chain                         |
| `user`             | string  | User address to configure            |
| `enabled`          | boolean | `true` to enable, `false` to disable |
| `nonce`            | number  | Transaction nonce                    |

## Use Cases

### Portfolio Margin Adoption

Track portfolio margin usage:

```python
def process_userPortfolioMargin_action(action):
    user = action.get('user')
    enabled = action.get('enabled')
    status = 'enabled' if enabled else 'disabled'
    print(f"Portfolio margin {status} for {user[:10]}...")
```

## Related Action Payloads

- [updateLeverage](https://www.dwellir.com/docs/hyperliquid/updateLeverage) - Leverage settings
- [updateIsolatedMargin](https://www.dwellir.com/docs/hyperliquid/updateIsolatedMargin) - Isolated margin adjustments

---

## validatorL1Votes - HyperCore Info Endpoint

# validatorL1Votes - HyperCore Info Endpoint

Get validator voting information for L1 operations on Hyperliquid, including consensus data and validator participation.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `validatorL1Votes` endpoint is essential for:

- **Validator Monitoring** — Track validator voting activity and participation
- **Consensus Analysis** — Analyze voting patterns and consensus formation
- **Network Health** — Monitor validator coordination on L1 operations
- **Staking Insights** — Understand validator behavior for staking decisions

## Request Parameters

- `type` (`string, required`): parameter: Must be `"validatorL1Votes"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "validatorL1Votes"
}'
```

## Response Fields

- `votes` (`array, required`): Array of validator vote records for L1 operations

## Successful Response

```json
{
  "votes": []
}
```

## Common Use Cases

### 1. Monitor Validator Participation

Track validator activity on L1 operations:

```javascript
async function monitorValidatorActivity() {
  const data = await getValidatorL1Votes();

  console.log('=== Validator L1 Voting Activity ===\n');
  console.log(`Total vote records: ${data.votes.length}`);

  if (data.votes.length === 0) {
    console.log('No recent L1 voting activity');
  }
}
```

### 2. Analyze Consensus Patterns

Analyze voting patterns and consensus formation:

```javascript
async function analyzeConsensus() {
  const data = await getValidatorL1Votes();

  return {
    totalVotes: data.votes.length,
    timestamp: Date.now(),
    hasActivity: data.votes.length > 0
  };
}

// Usage
const analysis = await analyzeConsensus();
console.log(`Consensus analysis:`, analysis);
```

### 3. Build Validator Dashboard

Create a monitoring dashboard for validators:

```javascript
async function getValidatorDashboard() {
  try {
    const votes = await getValidatorL1Votes();

    return {
      status: 'operational',
      voteCount: votes.votes.length,
      lastUpdated: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message
    };
  }
}
```

## Best Practices

1. **Poll regularly** — Monitor validator activity at consistent intervals
2. **Cache appropriately** — Cache results for several minutes to reduce load
3. **Handle empty responses** — Account for periods with no L1 voting activity
4. **Implement timeouts** — Use reasonable timeout values (10-30 seconds)
5. **Monitor trends** — Track voting patterns over time for insights

## Related Endpoints

- [**delegatorSummary**](https://www.dwellir.com/docs/hyperliquid/delegator-summary) — Get delegation summary information
- [**delegations**](https://www.dwellir.com/docs/hyperliquid/delegations) — Get staking delegation details
- [**meta**](https://www.dwellir.com/docs/hyperliquid/meta) — Get trading pair metadata

***

*Access real-time Hyperliquid validator information with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## ValidatorSignWithdrawalAction payload - Withdrawal Signatures

# ValidatorSignWithdrawalAction payload - Withdrawal Signatures

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `ValidatorSignWithdrawalAction` payload records a validator signature that authorizes an external bridge withdrawal.

## Sample Data

```json
{
  "signature": {
    "r": "0x62a3295228b569f9a08d3776a12bbb2bd56e75153c3dadefda97e84c1be87097",
    "s": "0x5b7d385d6e32cbb89ed5fad01877ca78bf562e1333ae16fb1bcb7eca946ed7c6",
    "v": 28
  },
  "action": {
    "type": "ValidatorSignWithdrawalAction",
    "user": "0x6275c773fa0d1fd29e39322afee475827171c26b",
    "destination": "0xc2c9981b9061e533affaaf03105c561154f1ec84",
    "usd": 15494002,
    "nonce": 1768146916924000,
    "signature": {
      "r": "0x1e63066eff19a658f69813bf33d081f856846c684e1488b1d021ec5419ba2f0c",
      "s": "0x8a56ce8e4ff9f0115fdef290e6ea2cc4364d9d0faa406a255a8f13df936a16d",
      "v": 28
    }
  },
  "nonce": 1768146734592
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xd0629981833e39c6d1dc0433264532010900b1671e315898742b44d4423213b1)

## Field Reference

### Action Fields

| Field         | Type   | Description                              |
| ------------- | ------ | ---------------------------------------- |
| `type`        | string | Always `"ValidatorSignWithdrawalAction"` |
| `user`        | string | User requesting withdrawal               |
| `destination` | string | External destination address             |
| `nonce`       | number | Withdrawal nonce                         |
| `usd`         | number | Amount in raw units                      |

## Use Cases

### Withdrawal Authorization Tracking

Monitor validator withdrawal signatures:

```python
def process_ValidatorSignWithdrawalAction(action):
    user = action.get('user')
    amount = action.get('usd') / 1_000_000
    print(f"Withdrawal signed: ${amount:,.2f} for {user[:10]}...")
```

## Related Action Payloads

- [withdraw3](https://www.dwellir.com/docs/hyperliquid/withdraw3) - External withdrawal initiation
- [VoteEthFinalizedWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/VoteEthFinalizedWithdrawalAction) - Finalization votes

---

## vaultSummaries - HyperCore Info Endpoint

# vaultSummaries - HyperCore Info Endpoint

Get comprehensive summary information for all vaults on the platform, including performance metrics, total value locked, and vault characteristics.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `vaultSummaries` endpoint is essential for vault aggregators, analytics platforms, and DeFi dashboards who need to:

- **Aggregate Vault Data** — Get complete overview of all available vaults
- **Build Vault Explorers** — Create searchable vault directories
- **Track Market Growth** — Monitor total vault ecosystem metrics
- **Portfolio Diversification** — Discover vaults across different strategies

## Request Parameters

- `type` (`string, required`): parameter: Must be `"vaultSummaries"`

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "vaultSummaries"
}'
```

## Response Fields

- `vaultAddress` (`string, required`): Ethereum address of the vault contract
- `name` (`string, required`): Name of the vault
- `tvl` (`string, required`): Total value locked in USD
- `apy` (`string, required`): Annual percentage yield
- `totalDeposits` (`string, required`): Cumulative deposits in USD
- `totalWithdrawals` (`string, required`): Cumulative withdrawals in USD
- `netDeposits` (`string, required`): Net deposits (deposits - withdrawals)
- `sharePrice` (`string, required`): Current share price
- `totalShares` (`string, required`): Total shares outstanding
- `inception` (`string, required`): Vault creation date (ISO 8601)
- `performanceFee` (`string, required`): Performance fee percentage
- `managementFee` (`string, required`): Management fee percentage
- `minDeposit` (`string, required`): Minimum deposit amount in USD
- `depositLockup` (`string, required`): Lockup period in days

## Successful Response

```json
[
  {
    "vaultAddress": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Alpha Strategy Vault",
    "tvl": "5000000.00",
    "apy": "45.2",
    "totalDeposits": "4800000.00",
    "totalWithdrawals": "200000.00",
    "netDeposits": "4600000.00",
    "sharePrice": "1.15",
    "totalShares": "4347826.09",
    "inception": "2024-01-15",
    "performanceFee": "20",
    "managementFee": "2",
    "minDeposit": "1000.00",
    "depositLockup": "7"
  },
  {
    "vaultAddress": "0xabcdef1234567890abcdef1234567890abcdef12",
    "name": "Delta Neutral Vault",
    "tvl": "3500000.00",
    "apy": "28.7",
    "totalDeposits": "3200000.00",
    "totalWithdrawals": "100000.00",
    "netDeposits": "3100000.00",
    "sharePrice": "1.09",
    "totalShares": "3211009.17",
    "inception": "2024-02-20",
    "performanceFee": "15",
    "managementFee": "1.5",
    "minDeposit": "500.00",
    "depositLockup": "3"
  }
]
```

## Common Use Cases

### 1. Find Vaults by Investment Criteria

Filter vaults based on specific requirements:

```javascript
async function findVaultsByCriteria(criteria) {
  const vaults = await getVaultSummaries();

  return vaults.filter(v => {
    const tvl = parseFloat(v.tvl);
    const apy = parseFloat(v.apy);
    const minDeposit = parseFloat(v.minDeposit);
    const lockup = parseInt(v.depositLockup);
    const perfFee = parseFloat(v.performanceFee);

    // Check all criteria
    if (criteria.minTVL && tvl < criteria.minTVL) return false;
    if (criteria.minAPY && apy < criteria.minAPY) return false;
    if (criteria.maxMinDeposit && minDeposit > criteria.maxMinDeposit) return false;
    if (criteria.maxLockup && lockup > criteria.maxLockup) return false;
    if (criteria.maxPerformanceFee && perfFee > criteria.maxPerformanceFee) return false;

    return true;
  });
}

// Usage
const suitableVaults = await findVaultsByCriteria({
  minTVL: 1000000,        // At least $1M TVL
  minAPY: 25,             // At least 25% APY
  maxMinDeposit: 5000,    // Max $5k minimum deposit
  maxLockup: 7,           // Max 7 days lockup
  maxPerformanceFee: 20   // Max 20% performance fee
});

console.log(`Found ${suitableVaults.length} vaults matching criteria`);
suitableVaults.forEach(v => {
  console.log(`${v.name}: ${v.apy}% APY, $${v.tvl} TVL`);
});
```

### 2. Analyze Vault Growth Metrics

Track vault growth and capital flows:

```javascript
async function analyzeVaultGrowth() {
  const vaults = await getVaultSummaries();

  const analysis = vaults.map(v => {
    const tvl = parseFloat(v.tvl);
    const netDeposits = parseFloat(v.netDeposits);
    const sharePrice = parseFloat(v.sharePrice);

    // Calculate returns from share price
    const returns = ((sharePrice - 1) / 1) * 100;

    // Calculate growth from trading vs deposits
    const tradingGains = tvl - netDeposits;
    const growthFromTrading = (tradingGains / netDeposits) * 100;

    return {
      name: v.name,
      tvl: tvl,
      netDeposits: netDeposits,
      tradingGains: tradingGains,
      returns: returns.toFixed(2),
      growthFromTrading: growthFromTrading.toFixed(2),
      depositorCount: Math.round(netDeposits / parseFloat(v.minDeposit))
    };
  });

  return analysis.sort((a, b) => b.growthFromTrading - a.growthFromTrading);
}

// Usage
const growth = await analyzeVaultGrowth();
console.log('\n=== Vaults with Highest Trading Gains ===');
growth.slice(0, 5).forEach((v, i) => {
  console.log(`\n${i + 1}. ${v.name}`);
  console.log(`   Trading Gains: $${v.tradingGains.toLocaleString()}`);
  console.log(`   Growth from Trading: ${v.growthFromTrading}%`);
  console.log(`   Total Returns: ${v.returns}%`);
});
```

### 3. Compare Fee Structures

Analyze and compare vault fee models:

```javascript
async function analyzeFeeStructures() {
  const vaults = await getVaultSummaries();

  const feeAnalysis = vaults.map(v => {
    const apy = parseFloat(v.apy);
    const perfFee = parseFloat(v.performanceFee);
    const mgmtFee = parseFloat(v.managementFee);
    const tvl = parseFloat(v.tvl);

    // Estimate annual fees
    const annualMgmtFee = tvl * (mgmtFee / 100);
    const estimatedPerfFee = tvl * (apy / 100) * (perfFee / 100);
    const totalAnnualFees = annualMgmtFee + estimatedPerfFee;

    // Net APY after fees
    const grossReturns = tvl * (apy / 100);
    const netReturns = grossReturns - totalAnnualFees;
    const netAPY = (netReturns / tvl) * 100;

    return {
      name: v.name,
      grossAPY: apy,
      netAPY: netAPY.toFixed(2),
      perfFee: perfFee,
      mgmtFee: mgmtFee,
      totalFeesUSD: totalAnnualFees.toFixed(2),
      feeImpact: ((apy - netAPY) / apy * 100).toFixed(2)
    };
  });

  // Sort by net APY
  return feeAnalysis.sort((a, b) => parseFloat(b.netAPY) - parseFloat(a.netAPY));
}

// Usage
const feeAnalysis = await analyzeFeeStructures();
console.log('\n=== Best Net Returns After Fees ===');
feeAnalysis.slice(0, 5).forEach((v, i) => {
  console.log(`\n${i + 1}. ${v.name}`);
  console.log(`   Gross APY: ${v.grossAPY}%`);
  console.log(`   Net APY: ${v.netAPY}%`);
  console.log(`   Fee Impact: ${v.feeImpact}%`);
});
```

### 4. Track Market Concentration

Analyze TVL distribution across vaults:

```javascript
async function analyzeMarketConcentration() {
  const vaults = await getVaultSummaries();

  // Sort by TVL
  const sortedVaults = [...vaults].sort((a, b) =>
    parseFloat(b.tvl) - parseFloat(a.tvl)
  );

  const totalTVL = vaults.reduce((sum, v) => sum + parseFloat(v.tvl), 0);

  // Calculate concentration metrics
  const top5TVL = sortedVaults.slice(0, 5).reduce((sum, v) =>
    sum + parseFloat(v.tvl), 0
  );
  const top10TVL = sortedVaults.slice(0, 10).reduce((sum, v) =>
    sum + parseFloat(v.tvl), 0
  );

  const concentration = {
    totalVaults: vaults.length,
    totalTVL: totalTVL,
    top5Share: ((top5TVL / totalTVL) * 100).toFixed(2),
    top10Share: ((top10TVL / totalTVL) * 100).toFixed(2),
    avgTVL: (totalTVL / vaults.length).toFixed(2),
    medianTVL: parseFloat(sortedVaults[Math.floor(vaults.length / 2)].tvl)
  };

  return {
    ...concentration,
    topVaults: sortedVaults.slice(0, 5).map(v => ({
      name: v.name,
      tvl: parseFloat(v.tvl),
      marketShare: ((parseFloat(v.tvl) / totalTVL) * 100).toFixed(2)
    }))
  };
}

// Usage
const concentration = await analyzeMarketConcentration();
console.log('\n=== Market Concentration ===');
console.log(`Total TVL: $${concentration.totalTVL.toLocaleString()}`);
console.log(`Top 5 control: ${concentration.top5Share}%`);
console.log(`Top 10 control: ${concentration.top10Share}%`);

console.log('\n=== Top 5 Vaults ===');
concentration.topVaults.forEach((v, i) => {
  console.log(`${i + 1}. ${v.name}: ${v.marketShare}% market share`);
});
```

### 5. Build Vault Comparison Tool

Create a comprehensive vault comparison:

```javascript
async function compareVaults(vaultAddresses) {
  const allVaults = await getVaultSummaries();

  const selectedVaults = allVaults.filter(v =>
    vaultAddresses.includes(v.vaultAddress)
  );

  const comparison = selectedVaults.map(v => {
    const tvl = parseFloat(v.tvl);
    const apy = parseFloat(v.apy);
    const sharePrice = parseFloat(v.sharePrice);
    const perfFee = parseFloat(v.performanceFee);
    const mgmtFee = parseFloat(v.managementFee);

    // Calculate net APY after fees
    const grossReturns = tvl * (apy / 100);
    const annualFees = tvl * (mgmtFee / 100) + grossReturns * (perfFee / 100);
    const netAPY = ((grossReturns - annualFees) / tvl) * 100;

    return {
      name: v.name,
      address: v.vaultAddress,
      tvl: tvl,
      apy: apy,
      netAPY: netAPY.toFixed(2),
      sharePrice: sharePrice,
      returns: ((sharePrice - 1) * 100).toFixed(2),
      minDeposit: parseFloat(v.minDeposit),
      lockup: parseInt(v.depositLockup),
      fees: `${perfFee}% perf / ${mgmtFee}% mgmt`,
      inception: v.inception
    };
  });

  return comparison;
}

// Usage
const vaultsToCompare = [
  '0x1234567890abcdef1234567890abcdef12345678',
  '0xabcdef1234567890abcdef1234567890abcdef12'
];

const comparison = await compareVaults(vaultsToCompare);
console.log('\n=== Vault Comparison ===');
comparison.forEach(v => {
  console.log(`\n${v.name}`);
  console.log(`TVL: $${v.tvl.toLocaleString()}`);
  console.log(`Gross APY: ${v.apy}% | Net APY: ${v.netAPY}%`);
  console.log(`Returns: ${v.returns}%`);
  console.log(`Min Deposit: $${v.minDeposit} | Lockup: ${v.lockup} days`);
  console.log(`Fees: ${v.fees}`);
});
```

## Best Practices

1. **Cache appropriately** — Vault summaries can be cached for 5-15 minutes
2. **Consider fees** — Always calculate net returns after fees
3. **Check liquidity** — Verify TVL is sufficient for your deposit size
4. **Review lockups** — Ensure lockup periods match your investment timeline
5. **Monitor growth** — Track both deposit growth and trading performance

## Related Endpoints

- [**leadingVaults**](https://www.dwellir.com/docs/hyperliquid/leading-vaults) — Get top-performing vaults
- [**userVaultEquities**](https://www.dwellir.com/docs/hyperliquid/user-vault-equities) — Get user's vault positions
- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get user's perpetual account state

***

*Access comprehensive Hyperliquid vault data with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## vaultTransfer payload - Vault Transfers

# vaultTransfer payload - Vault Transfers

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `vaultTransfer` payload records a deposit to or withdrawal from a Hyperliquid vault.

## Sample Data

```json
{
  "signature": {
    "r": "0xb2eaf71a6dd711b38983c5ca9c813e6260cd11414d5b66bfc734ccf27671858c",
    "s": "0x77e7d3501bc1c6743787a1967dcdc0618f0f445df70bb98b99dccc66881d4b33",
    "v": 28
  },
  "action": {
    "type": "vaultTransfer",
    "vaultAddress": "0xdfc24b077bc1425ad1dea75bcb6f8158e10df303",
    "isDeposit": false,
    "usd": 500000000
  },
  "nonce": 1768147192344,
  "expiresAfter": 1768147206900
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x4bdc0ce600639cb74d5504332652ab02013700cb9b66bb89efa4b838bf6776a1)

## Field Reference

### Action Fields

| Field          | Type    | Description                                            |
| -------------- | ------- | ------------------------------------------------------ |
| `type`         | string  | Always `"vaultTransfer"`                               |
| `vaultAddress` | string  | Ethereum address of the vault                          |
| `isDeposit`    | boolean | `true` for deposit, `false` for withdrawal             |
| `usd`          | number  | Amount in raw units (6 decimals, so 50000000 = 50 USD) |

### Optional Fields

| Field          | Type   | Description                                |
| -------------- | ------ | ------------------------------------------ |
| `expiresAfter` | number | Timestamp after which the transfer expires |

## Amount Conversion

The `usd` field uses 6 decimal places:

- `50000000` = 50.00 USD
- `1000000` = 1.00 USD
- `1000000000` = 1,000.00 USD

## Use Cases

### Vault Flow Analysis

Track capital flows into and out of vaults:

```python
def process_vaultTransfer_action(action):
    vault = action.get('vaultAddress')
    amount = action.get('usd') / 1_000_000  # Convert to USD
    direction = 'deposit' if action.get('isDeposit') else 'withdrawal'

    print(f"Vault {direction}: ${amount:,.2f} to {vault[:10]}...")
```

### Fund Manager Performance

Monitor vault deposit/withdrawal patterns to understand:

- Vault popularity and AUM trends
- Investor confidence in vault strategies
- Capital rotation between vaults

### Copy Trading Analysis

Track which vaults are attracting deposits to identify successful trading strategies.

## Related Action Payloads

- [NetChildVaultPositionsAction](https://www.dwellir.com/docs/hyperliquid/NetChildVaultPositionsAction) - Net child vault positions
- [subAccountTransfer](https://www.dwellir.com/docs/hyperliquid/subAccountTransfer) - Main-account and sub-account transfers

---

## voteAppHash payload - Validator State Votes

# voteAppHash payload - Validator State Votes

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `voteAppHash` payload records a validator vote on an application-state hash.

## Sample Data

```json
{
  "signature": {
    "r": "0xccd84bb5e2f144ec741af1a81d2fc318d8ccb75eaf500371c1515c1e695b2213",
    "s": "0x25a8b7da621dccbd161fb61487c6bd8e369d1ba28567b26b3ac6ab647b84e270",
    "v": 28
  },
  "action": {
    "type": "voteAppHash",
    "height": 858146000,
    "appHash": "0x9133a75f5e126769845b4bd35e7b6b02456c1f3df72f146eb89e0e86c61415d7",
    "signature": {
      "r": "0x381dcf885e27e08f1547ded9a97f3d51eef2857d86164993d8416c2deeeb8de1",
      "s": "0x4ad114432fef3b53b791a568a118f99ec881922ce57fa2e2df1f4fb9272c609f",
      "v": 27
    }
  },
  "nonce": 1768146734574
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0xc871b17a2a660c12c9eb0433264507010b00c95fc5692ae46c3a5ccce969e5fd)

## Field Reference

### Action Fields

| Field       | Type   | Description                       |
| ----------- | ------ | --------------------------------- |
| `type`      | string | Always `"voteAppHash"`            |
| `height`    | number | Block height being voted on       |
| `appHash`   | string | Application state hash            |
| `signature` | object | Validator's signature on the vote |

## Use Cases

### Consensus Monitoring

Track validator voting activity:

```python
def process_voteAppHash_action(action):
    height = action.get('height')
    app_hash = action.get('appHash')
    print(f"State vote: height {height}, hash {app_hash[:20]}...")
```

## Related Action Payloads

- [VoteEthDepositAction](https://www.dwellir.com/docs/hyperliquid/VoteEthDepositAction) - Validator deposit votes
- [tokenDelegate](https://www.dwellir.com/docs/hyperliquid/tokenDelegate) - Token staking

---

## VoteEthDepositAction payload - Validator Deposit Votes

# VoteEthDepositAction payload - Validator Deposit Votes

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `VoteEthDepositAction` payload records a validator vote confirming an ETH deposit from the bridge contract.

## Sample Data

```json
{
  "signature": {
    "r": "0x74e0218199716f8217518bcb72240de1c17ff6e6682fbacdd820e60c13ac0454",
    "s": "0x4a5a442f5dad771b48f3852b4d96cc561de2804b6c1853e8d1548015a732b89f",
    "v": 28
  },
  "action": {
    "type": "VoteEthDepositAction",
    "user": "0x09a8c041c8d966ddb20b2ea5b556ef0318365182",
    "usd": 90391034,
    "ethId": {
      "block_number": 420281244,
      "tx_index": 25,
      "event_type": "Deposit",
      "event_index": 0,
      "tx_hash": "0x107c5fc0f824b2993b28ade0560cb732b0f25df4a47a777c47be108c432ce933"
    }
  },
  "nonce": 1768146734681
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x13362fd89699384714af043326473502016000be319c5719b6fedb2b559d1231)

## Field Reference

### Action Fields

| Field       | Type   | Description                                 |
| ----------- | ------ | ------------------------------------------- |
| `type`      | string | Always `"VoteEthDepositAction"`             |
| `user`      | string | Address of the user who made the deposit    |
| `usd`       | number | Deposit amount in raw units (6 decimals)    |
| `ethTxHash` | string | Transaction hash of the deposit on Arbitrum |

## Bridge Consensus Process

1. User deposits funds to bridge contract on Arbitrum
2. Validators observe the deposit transaction
3. Validators submit `VoteEthDepositAction` votes
4. Once threshold is reached, funds are credited on Hyperliquid

## Use Cases

### Bridge Monitoring

Track deposit confirmations across the bridge:

```python
def process_VoteEthDepositAction(action):
    user = action.get('user')
    amount = action.get('usd') / 1_000_000
    eth_tx = action.get('ethTxHash')

    print(f"Deposit vote: ${amount:,.2f} for {user[:10]}... (tx: {eth_tx[:10]}...)")
```

### Validator Activity Tracking

Monitor which validators are actively participating in bridge consensus.

### Deposit Latency Analysis

Track time from Arbitrum transaction to Hyperliquid credit.

## Related Action Payloads

- [VoteEthFinalizedWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/VoteEthFinalizedWithdrawalAction) - Withdrawal votes
- [ValidatorSignWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/ValidatorSignWithdrawalAction) - Withdrawal signatures
- [voteAppHash](https://www.dwellir.com/docs/hyperliquid/voteAppHash) - Application state votes

---

## VoteEthFinalizedWithdrawalAction payload - Withdrawal Votes

# VoteEthFinalizedWithdrawalAction payload - Withdrawal Votes

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `VoteEthFinalizedWithdrawalAction` payload records a validator vote confirming that an Arbitrum withdrawal has finalized.

## Sample Data

```json
{
  "signature": {
    "r": "0x8e85e979af4151570ff20d1c17d380cd244f7b373df4082de4a271f2df8c2e3b",
    "s": "0x5855f07fcaf680d3213b3aea27c4b51cbfcd5681678a3b3264ad71a39d245c4c",
    "v": 28
  },
  "action": {
    "type": "VoteEthFinalizedWithdrawalAction",
    "user": "0xe095f4cc38ae81839c368a83ad906544aed36564",
    "destination": "0xe095f4cc38ae81839c368a83ad906544aed36564",
    "nonce": 1768146676227000,
    "usd": 15082681,
    "ethTxHash": "0xac1d8a6cea30fcce8527c823941239c621075ddcaebd8347ef8aa2df03659ea8"
  },
  "nonce": 1768146734586
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x7aaa86d76798832d7c24043326280a0107009ebd029ba1ff1e73322a269c5d18)

## Field Reference

### Action Fields

| Field         | Type   | Description                                      |
| ------------- | ------ | ------------------------------------------------ |
| `type`        | string | Always `"VoteEthFinalizedWithdrawalAction"`      |
| `user`        | string | Address of the user who initiated the withdrawal |
| `destination` | string | Destination address on Arbitrum                  |
| `nonce`       | number | Withdrawal nonce                                 |
| `usd`         | number | Withdrawal amount in raw units (6 decimals)      |
| `ethTxHash`   | string | Transaction hash of the withdrawal on Arbitrum   |

## Withdrawal Finalization Process

1. User submits [withdraw3](https://www.dwellir.com/docs/hyperliquid/withdraw3) action
2. Validators sign the withdrawal ([ValidatorSignWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/ValidatorSignWithdrawalAction))
3. Bridge transaction executes on Arbitrum
4. Validators vote to confirm finalization (`VoteEthFinalizedWithdrawalAction`)
5. Withdrawal is marked complete

## Use Cases

### Withdrawal Completion Tracking

Monitor withdrawal finalization:

```python
def process_VoteEthFinalizedWithdrawalAction(action):
    user = action.get('user')
    destination = action.get('destination')
    amount = action.get('usd') / 1_000_000

    print(f"Withdrawal finalized: ${amount:,.2f} from {user[:10]}... to {destination[:10]}...")
```

### Bridge Health Monitoring

Track withdrawal finalization rates and latencies.

### Validator Consensus Analysis

Monitor validator participation in withdrawal confirmations.

## Related Action Payloads

- [withdraw3](https://www.dwellir.com/docs/hyperliquid/withdraw3) - External withdrawal initiation
- [ValidatorSignWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/ValidatorSignWithdrawalAction) - Validator signs withdrawal
- [VoteEthDepositAction](https://www.dwellir.com/docs/hyperliquid/VoteEthDepositAction) - Validator deposit votes

---

## webData2 - HyperCore Info Endpoint

# webData2 - HyperCore Info Endpoint

Get the `webData2` envelope for a user. In practice this payload is a sparse top-level object, so treat it as a lightweight web-client response rather than a guaranteed all-in-one dashboard snapshot.

Depending on the account and current product rollout, the live response can expose fields such as `clearinghouseState`, `openOrders`, `assetCtxs`, `meta`, and `perpsAtOpenInterestCap` without promising that every field is populated for every address.

Authenticate by including your Dwellir API key in the URL path: `https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info`.

## When to Use This Endpoint

The `webData2` endpoint is most useful when you want to:

- **Bootstrap Web UI State** — Fetch a user-scoped response used by Hyperliquid web clients
- **Check for Available Web Payload Data** — Read whatever envelope data the service currently exposes for an address
- **Reduce One-Off Probing Calls** — Replace ad hoc exploratory requests with a single typed lookup

## Request Parameters

- `type` (`string, required`): parameter: Must be `"webData2"`
- `user` (`string, required`): parameter: User's Ethereum wallet address

## Request Example

```bash
curl -X POST "https://api-hyperliquid-mainnet-info.n.dwellir.com/YOUR_API_KEY/info" \
  -H "content-type: application/json" \
  -d '{
  "type": "webData2",
  "user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'
```

## Response Fields

- `clearinghouseState` (`object, optional`): Optional account-state payload with balances, margin summaries, positions, and withdrawable amounts
- `openOrders` (`array, optional`): Optional list of currently open orders for the requested address
- `assetCtxs` (`array, optional`): Optional asset-context snapshots used by web clients for market state
- `meta` (`object, optional`): Optional market metadata snapshot included alongside the web payload
- `perpsAtOpenInterestCap` (`array, optional`): Optional list of perpetual markets that are currently at their open-interest cap
- `user` (`string, optional`): User address echoed by the service when available
- `serverTime` (`integer, optional`): Server timestamp in milliseconds when included in the response
- `leadingVaults` (`array, optional`): Optional vault leaderboard snapshot for the current account context
- `totalVaultEquity` (`string, optional`): Optional total vault equity value when the account participates in vault features
- `agentAddress` (`string, optional`): Optional agent address associated with the account
- `agentValidUntil` (`integer, optional`): Optional expiration timestamp for the active agent configuration
- `isVault` (`boolean, optional`): Optional vault flag for the requested address
- `twapStates` (`array, optional`): Optional TWAP state snapshot when the service exposes it
- `cumLedger` (`array, optional`): Optional cumulative ledger entries returned for the current account context
- `crossMaintenanceMarginUsed` (`string, optional`): Optional top-level cross maintenance margin figure when included by the service
- `time` (`integer, optional`): Optional top-level timestamp when included by the service

## Successful Response

```json
{
  "user": "0x0000000000000000000000000000000000000000",
  "serverTime": 1773842240989,
  "assetCtxs": [],
  "openOrders": [],
  "perpsAtOpenInterestCap": ["CANTO", "FTM", "JELLY"],
  "clearinghouseState": {
    "marginSummary": {
      "accountValue": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "0.0",
      "totalMarginUsed": "0.0"
    },
    "crossMarginSummary": {
      "accountValue": "0.0",
      "totalNtlPos": "0.0",
      "totalRawUsd": "0.0",
      "totalMarginUsed": "0.0"
    },
    "crossMaintenanceMarginUsed": "0.0",
    "withdrawable": "0.0",
    "assetPositions": [],
    "time": 1773842240989
  },
  "meta": {
    "universe": [
      {
        "name": "BTC",
        "szDecimals": 5,
        "maxLeverage": 40,
        "marginTableId": 56
      }
    ]
  }
}
```

## Common Use Cases

### 1. Load the Current Envelope

Load the current `webData2` response for a user:

```javascript
async function loadUserDashboard(userAddress) {
  const webData = await getWebData2(userAddress);

  console.log('webData2 loaded');
  return webData;
}

// Usage
const dashboardData = await loadUserDashboard('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
```

### 2. Initialize a Web Client Cache

Bootstrap a web client with the available `webData2` payload:

```javascript
class WebInterface {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.data = null;
  }

  async initialize() {
    console.log('Initializing web interface...');
    this.data = await getWebData2(this.userAddress);
    console.log('Interface ready');
    return this.data;
  }

  getData() {
    return this.data;
  }

  async refresh() {
    console.log('Refreshing data...');
    this.data = await getWebData2(this.userAddress);
    return this.data;
  }
}

// Usage
const interface = new WebInterface('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
await interface.initialize();
```

### 3. Periodic Data Refresh

Refresh dashboard data at intervals:

```javascript
class DashboardDataManager {
  constructor(userAddress, refreshIntervalMs = 30000) {
    this.userAddress = userAddress;
    this.refreshIntervalMs = refreshIntervalMs;
    this.currentData = null;
    this.onUpdate = null;
  }

  async start(updateCallback) {
    this.onUpdate = updateCallback;

    // Initial load
    await this.refresh();

    // Periodic refresh
    setInterval(() => this.refresh(), this.refreshIntervalMs);
  }

  async refresh() {
    try {
      this.currentData = await getWebData2(this.userAddress);

      if (this.onUpdate) {
        this.onUpdate(this.currentData);
      }

      return this.currentData;
    } catch (error) {
      console.error('Failed to refresh data:', error);
    }
  }

  getCurrentData() {
    return this.currentData;
  }
}

// Usage
const manager = new DashboardDataManager('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
manager.start((data) => {
  console.log('Dashboard data updated');
  // Update UI with new data
});
```

### 4. Check Whether Payload Data Exists

Check whether a user currently has any `webData2` payload available:

```javascript
async function buildTradingInterface(userAddress) {
  try {
    const webData = await getWebData2(userAddress);

    return {
      status: 'success',
      data: webData,
      hasData: Boolean(
        webData.clearinghouseState ||
          (Array.isArray(webData.openOrders) && webData.openOrders.length > 0) ||
          (Array.isArray(webData.assetCtxs) && webData.assetCtxs.length > 0)
      ),
      lastUpdated: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message,
      hasData: false
    };
  }
}

// Usage
const tradingInterface = await buildTradingInterface('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');

if (tradingInterface.status === 'success') {
  console.log('webData2 request succeeded');
} else {
  console.error('Failed to load interface:', tradingInterface.error);
}
```

### 5. Cache-Optimized Data Loading

Implement efficient caching for web data:

```javascript
class CachedWebDataLoader {
  constructor(userAddress, cacheDurationMs = 60000) {
    this.userAddress = userAddress;
    this.cacheDurationMs = cacheDurationMs;
    this.cache = null;
    this.cacheTime = 0;
  }

  async load(forceRefresh = false) {
    const now = Date.now();
    const cacheAge = now - this.cacheTime;

    if (!forceRefresh && this.cache && cacheAge < this.cacheDurationMs) {
      console.log(`Using cached data (age: ${Math.round(cacheAge / 1000)}s)`);
      return this.cache;
    }

    console.log('Loading fresh data...');
    const data = await getWebData2(this.userAddress);

    this.cache = data;
    this.cacheTime = now;

    return data;
  }

  invalidateCache() {
    this.cache = null;
    this.cacheTime = 0;
  }
}

// Usage
const loader = new CachedWebDataLoader('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
const data = await loader.load(); // Fresh load
const cachedData = await loader.load(); // From cache
```

## Best Practices

1. **Expect sparse payloads** — Handle partially populated top-level objects without treating missing fields as errors
2. **Validate addresses** — Ensure user addresses are valid before requests
3. **Cache conservatively** — Refresh only as often as your UI actually needs
4. **Avoid assuming schema stability** — Prefer defensive parsing over tightly coupled field access
5. **Combine with specific endpoints** — Use dedicated info endpoints for positions, orders, or fees when you need guaranteed fields

## Performance Tips

### Efficient Dashboard Updates

```javascript
class EfficientDashboard {
  constructor(userAddress) {
    this.userAddress = userAddress;
    this.lastData = null;
  }

  async update() {
    const newData = await getWebData2(this.userAddress);

    // Compare with previous data
    const hasChanged = JSON.stringify(newData) !== JSON.stringify(this.lastData);

    if (hasChanged) {
      console.log('Data changed - updating UI');
      this.lastData = newData;
      return { changed: true, data: newData };
    }

    console.log('No changes detected');
    return { changed: false, data: newData };
  }
}
```

## Related Endpoints

- [**clearinghouseState**](https://www.dwellir.com/docs/hyperliquid/clearinghouse-state) — Get detailed account state
- [**openOrders**](https://www.dwellir.com/docs/hyperliquid/open-orders) — Get open orders separately
- [**userFees**](https://www.dwellir.com/docs/hyperliquid/user-fees) — Get fee information
- [**spotClearinghouseState**](https://www.dwellir.com/docs/hyperliquid/spot-clearinghouse-state) — Get spot balances

***

*Build resilient Hyperliquid integrations with Dwellir's HyperCore Info Endpoint. [Get your API key →](https://dashboard.dwellir.com/register)*

---

## web3_clientVersion - Hyperliquid RPC Method

# web3_clientVersion - Hyperliquid RPC Method

Returns the current client software version string for your Hyperliquid node, including the client name, version number, OS, and runtime.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

## When to Use This Method

`web3_clientVersion` is valuable for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Hyperliquid client:', clientVersion);

// Using fetch
const response = await fetch('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Hyperliquid client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Hyperliquid client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/hyperliquid/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/hyperliquid/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/hyperliquid/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/hyperliquid/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Hyperliquid RPC Method

# web3_sha3 - Hyperliquid RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Hyperliquid.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/hyperliquid/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/hyperliquid/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/hyperliquid/web3_clientVersion) - Get node client version

---

## WebSocket API Quick Reference

# WebSocket API Quick Reference

Quick reference for connecting to and using the Hyperliquid Order Book WebSocket API. For detailed documentation on each subscription type, see the individual pages.

## Detailed Documentation

| Subscription      | Description                 | Documentation                                                    |
| ----------------- | --------------------------- | ---------------------------------------------------------------- |
| **Trades**        | Real-time trade executions  | [View Trades Docs →](https://www.dwellir.com/docs/hyperliquid/trades) |
| **L2 Order Book** | Aggregated price levels     | [View L2 Docs →](https://www.dwellir.com/docs/hyperliquid/l2-book)    |
| **L4 Order Book** | Individual order visibility | [View L4 Docs →](https://www.dwellir.com/docs/hyperliquid/l4-book)    |

For an overview of all subscription types and use cases, see the [Order Book Server Overview](https://www.dwellir.com/docs/hyperliquid/order-book-server).

## Connection

```
wss://api-hyperliquid-mainnet-orderbook.n.dwellir.com/{API_KEY}/ws
```

Replace `{API_KEY}` with the API key from your [Dwellir dashboard](https://dashboard.dwellir.com). The Order Book add-on must be enabled on your API plan.

## Quick Start

Python
JavaScript

```python
import asyncio
import json
import websockets

async def main():
    ws_url = "wss://api-hyperliquid-mainnet-orderbook.n.dwellir.com/{API_KEY}/ws"

    async with websockets.connect(ws_url) as websocket:
        # Subscribe to BTC trades
        await websocket.send(json.dumps({
            "method": "subscribe",
            "subscription": {"type": "trades", "coin": "BTC"}
        }))

        async for message in websocket:
            print(json.loads(message))

asyncio.run(main())
```

```javascript
const WebSocket = require('ws');
const ws = new WebSocket('wss://api-hyperliquid-mainnet-orderbook.n.dwellir.com/{API_KEY}/ws');

ws.on('open', () => {
    ws.send(JSON.stringify({
        method: 'subscribe',
        subscription: { type: 'trades', coin: 'BTC' }
    }));
});

ws.on('message', (data) => console.log(JSON.parse(data)));
```

## Subscription Types

### Trades

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "trades",
    "coin": "BTC"
  }
}
```

| Parameter | Default  | Description                                                    |
| --------- | -------- | -------------------------------------------------------------- |
| `user`    | *(none)* | Optional. Filter to trades involving a specific wallet address |

[Full Trades Documentation →](https://www.dwellir.com/docs/hyperliquid/trades)

### L2 Order Book

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC",
    "nSigFigs": 5,
    "nLevels": 20
  }
}
```

| Parameter  | Default | Range | Description                           |
| ---------- | ------- | ----- | ------------------------------------- |
| `nSigFigs` | 5       | 2-5   | Price aggregation significant figures |
| `nLevels`  | 20      | 1-100 | Number of price levels per side       |

[Full L2 Documentation →](https://www.dwellir.com/docs/hyperliquid/l2-book)

### L4 Order Book

```json
{
  "method": "subscribe",
  "subscription": {
    "type": "l4Book",
    "coin": "BTC"
  }
}
```

[Full L4 Documentation →](https://www.dwellir.com/docs/hyperliquid/l4-book)

## Unsubscribe

```json
{
  "method": "unsubscribe",
  "subscription": {
    "type": "trades",
    "coin": "BTC"
  }
}
```

## Server Messages

### Subscription Confirmation

```json
{
  "channel": "subscriptionResponse",
  "data": {
    "method": "subscribe",
    "subscription": { "type": "trades", "coin": "BTC" }
  }
}
```

### Error Response

```json
{
  "channel": "error",
  "data": "Invalid subscription: coin not found"
}
```

### Common Errors

| Error                    | Cause                          |
| ------------------------ | ------------------------------ |
| `"coin not found"`       | Invalid trading pair symbol    |
| `"n_levels too high"`    | Requested more than 100 levels |
| `"Already subscribed"`   | Duplicate subscription         |
| `"Order book not ready"` | Server initializing            |

## Response Channels

| Channel                | Subscription Type          |
| ---------------------- | -------------------------- |
| `trades`               | Trades stream              |
| `l2Book`               | L2 order book              |
| `l4Book`               | L4 order book              |
| `subscriptionResponse` | Subscription confirmations |
| `error`                | Error messages             |

## Reconnection

The server may restart to resync state. Implement automatic reconnection:

```python
async def connect_with_retry():
    delay = 1
    while True:
        try:
            async with websockets.connect(ws_url) as ws:
                delay = 1  # Reset on success
                await handle_connection(ws)
        except Exception:
            await asyncio.sleep(delay)
            delay = min(delay * 2, 60)  # Exponential backoff
```

## Resources

- **[Code Examples](https://github.com/dwellir-public/hyperliquid-orderbook-server-code-examples)** - Complete Python examples
- **[Volume Calculator](https://www.dwellir.com/hyperliquid-orderbook#calculator)** - Estimate monthly usage
- **[Contact](mailto:support@dwellir.com)** - Get access credentials

***

*For detailed documentation, visit the individual subscription pages: [Trades](https://www.dwellir.com/docs/hyperliquid/trades) | [L2 Book](https://www.dwellir.com/docs/hyperliquid/l2-book) | [L4 Book](https://www.dwellir.com/docs/hyperliquid/l4-book)*

---

## withdraw3 payload - External Withdrawals

# withdraw3 payload - External Withdrawals

Dwellir's Hyperliquid gRPC API returns this decoded action payload through
[StreamBlocks](https://www.dwellir.com/docs/hyperliquid/stream_blocks) and
[GetBlock](https://www.dwellir.com/docs/hyperliquid/get_block). It does not submit or execute this action.
Submit supported user write actions through Hyperliquid's native
[`POST /exchange`](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint)
endpoint.

The decoded `withdraw3` payload records a request to bridge funds from Hyperliquid to an external Ethereum address.

## Sample Data

```json
{
  "signature": {
    "r": "0xbf01efa816fdc37c8eea7ae4893999cae61ead196013d4bcb36ff8aad3058650",
    "s": "0x2dcc0e2d708eccdf7ab68a23b99b4142aa6eca02141623851158821d371bd610",
    "v": 27
  },
  "action": {
    "type": "withdraw3",
    "signatureChainId": "0x66eee",
    "hyperliquidChain": "Mainnet",
    "destination": "0xc2c9981b9061e533affaaf03105c561154f1ec84",
    "amount": "16.494002",
    "time": 1768146916924
  },
  "nonce": 1768146916924
}
```

[View this transaction on Hypurrscan](https://hypurrscan.io/tx/0x0060497fdb8f86ee01da04332644fa0201ee00657682a5c0a428f4d29a8360d8)

## Field Reference

### Action Fields

| Field              | Type   | Description                                          |
| ------------------ | ------ | ---------------------------------------------------- |
| `type`             | string | Always `"withdraw3"`                                 |
| `signatureChainId` | string | Chain ID for signing (e.g., `"0xa4b1"` for Arbitrum) |
| `hyperliquidChain` | string | Source chain: `"Mainnet"` or `"Testnet"`             |
| `destination`      | string | External Ethereum address to receive funds           |
| `amount`           | string | Amount to withdraw in USD                            |
| `time`             | number | Transaction timestamp                                |

## Withdrawal Process

1. User submits `withdraw3` action
2. Validators verify the withdrawal request
3. Validators sign the withdrawal ([ValidatorSignWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/ValidatorSignWithdrawalAction))
4. Bridge transaction is executed on Arbitrum
5. Funds arrive at destination address

## Use Cases

### Withdrawal Monitoring

Track withdrawals leaving the platform:

```python
def process_withdraw3_action(action):
    destination = action.get('destination')
    amount = action.get('amount')

    print(f"Withdrawal: ${amount} to {destination}")
```

### Capital Flow Analysis

Monitor net flows in and out of Hyperliquid to understand market sentiment.

### Compliance Monitoring

Track withdrawal destinations for regulatory compliance.

## Related Action Payloads

- [ValidatorSignWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/ValidatorSignWithdrawalAction) - Validator withdrawal signatures
- [VoteEthFinalizedWithdrawalAction](https://www.dwellir.com/docs/hyperliquid/VoteEthFinalizedWithdrawalAction) - Finalized withdrawal votes
- [usdSend](https://www.dwellir.com/docs/hyperliquid/usdSend) - Internal USD transfers

---

## Immutable zkEVM - Gaming L2

# Immutable zkEVM - Gaming L2

## Immutable zkEVM RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Immutable zkEVM supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Immutable zkEVM?

Immutable zkEVM is the first EVM-compatible blockchain built specifically for gaming, offering seamless Web3 integration for game developers. Powered by zero-knowledge technology, Immutable zkEVM delivers:

### **Gaming-First Design**

- **Purpose-built for games** - Optimized infrastructure for gaming workloads
- **Seamless Web3 integration** - Add blockchain features without sacrificing UX
- **Developer-friendly tools** - Comprehensive SDK and gaming-specific APIs

### **High-Performance Infrastructure**

- **Instant transactions** - Fast block times for real-time gaming
- **Massive scale** - Handle thousands of concurrent players
- **Zero-knowledge proofs** - Efficient transaction batching and verification

### **Enterprise-Grade Security**

- **Ethereum security** - Inherits L1 security guarantees
- **Battle-tested technology** - Built on proven zkEVM architecture
- **Immutable backing** - Supported by leading Web3 gaming infrastructure

## Quick Start with Immutable zkEVM

Connect to Immutable zkEVM in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Immutable zkEVM mainnet
const provider = new JsonRpcProvider(
  'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Immutable zkEVM mainnet
const web3 = new Web3(
  'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Immutable zkEVM:', chainId === 13371);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { defineChain } from 'viem';

// Define Immutable zkEVM chain
const immutableZkEvm = defineChain({
  id: 13371,
  name: 'Immutable zkEVM',
  network: 'immutable-zkevm',
  nativeCurrency: { name: 'IMX', symbol: 'IMX', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'] },
    public: { http: ['https://rpc.immutable.com'] },
  },
  blockExplorers: {
    default: { name: 'Immutable Explorer', url: 'https://explorer.immutable.com' },
  },
});

// Create Immutable zkEVM client
const client = createPublicClient({
  chain: immutableZkEvm,
  transport: http('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 13371     | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | IMX       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Immutable zkEVM supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods optimized for gaming workloads.

## Common Integration Patterns

### Gaming Transaction Patterns

Handle high-frequency gaming transactions efficiently:

```javascript
// Batch multiple game actions in a single transaction
async function batchGameActions(actions) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Fast confirmation for real-time gaming
  console.log('Transaction confirmed in:', receipt.blockNumber);

  return receipt;
}
```

### NFT and Asset Management

Optimize for gaming assets and NFTs:

```javascript
// Efficient gas estimation for gaming transactions
const gasEstimate = await provider.estimateGas(tx);

// Immutable zkEVM optimized for gaming workloads
const optimizedGas = Math.ceil(gasEstimate * 1.1); // 10% buffer

// Set gas with gaming-optimized pricing
const txWithGas = {
  ...tx,
  gasLimit: optimizedGas,
  maxFeePerGas: await provider.getFeeData().maxFeePerGas
};
```

### Game Event Tracking

Efficiently query game-related events:

```javascript
// Query game events with optimized batching
async function getGameEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 5000; // Immutable zkEVM optimized batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class ImmutableProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds"

Immutable zkEVM transactions require IMX for gas fees:

```javascript
// Check IMX balance for gas fees
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + (tx.value || 0n);

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more IMX`);
}
```

### Error: "Transaction underpriced"

Immutable zkEVM uses EIP-1559 pricing with minimum 10 gwei priority fee:

```javascript
// Get current fee data with gaming-optimized settings
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: Math.max(
    feeData.maxPriorityFeePerGas,
    10000000000n // 10 gwei minimum
  ),
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Immutable zkEVM requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Immutable zkEVM)
const provider = new JsonRpcProvider(
  'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (13371)
// Note: Separate block numbers
// Note: IMX used for gas fees
// Note: Minimum 10 gwei priority fee
```

### From Other Gaming Chains

Migrating gaming applications to Immutable zkEVM:

```javascript
// Enhanced gaming features available
const gameContract = new Contract(address, abi, provider);

// Optimized for high-frequency gaming transactions
const batchTx = await gameContract.batchMint(
  playerAddresses,
  tokenIds,
  { gasLimit: 500000 } // Gaming-optimized gas limits
);
```

## Resources & Tools

### Official Resources

- [Immutable Documentation](https://docs.immutable.com)
- [Immutable Block Explorer](https://explorer.immutable.com)

### Developer Tools

- [Immutable SDK](https://docs.immutable.com/reference/typescript)
- [Unity SDK](https://docs.immutable.com/sdks/zkevm/unity/)
- [Passport Integration](https://docs.immutable.com/sdks/zkevm/unity/passport/)

### Gaming Ecosystem

- [Gods Unchained](https://godsunchained.com) - Leading TCG on Immutable
- [Guild of Guardians](https://guildofguardians.com) - Mobile RPG
- [Illuvium](https://illuvium.io) - Open-world RPG

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building games on Immutable zkEVM with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Immutable RPC Method

# debug_traceBlock - Immutable RPC Method

Traces all transactions in a block on Immutable by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Immutable - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Immutable
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Immutable:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Immutable blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/immutable/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/immutable/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/immutable/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/immutable/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Immutable RPC Method

# debug_traceBlockByHash - Immutable RPC Method

Traces all transactions in a block on Immutable identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Immutable - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Immutable
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Immutable:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Immutable:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/immutable/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/immutable/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/immutable/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/immutable/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/immutable/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Immutable RPC Method

# debug_traceBlockByNumber - Immutable RPC Method

Traces all transactions in a block on Immutable identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Immutable - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Immutable execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Immutable:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Immutable:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/immutable/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/immutable/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/immutable/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/immutable/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Immutable RPC Method

# debug_traceCall - Immutable RPC Method

Traces a call on Immutable without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Immutable - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Immutable
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "data": "0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
        "data": "0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
        "data": "0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    data: '0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    data: '0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    'data': '0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
        "data": "0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Immutable to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Immutable:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Immutable:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/immutable/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/immutable/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/immutable/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/immutable/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Immutable RPC Method

# debug_traceTransaction - Immutable RPC Method

Traces a transaction execution on Immutable by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Immutable
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/immutable/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/immutable/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Immutable RPC Method

# eth_accounts - Immutable RPC Method

Returns a list of addresses owned by the client on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/immutable/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/immutable/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Immutable RPC Method

# eth_blockNumber - Immutable RPC Method

Returns the number of the most recent block on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_blockNumber` is fundamental for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Syncing Applications** - Keep your dApp in sync with the latest Immutable blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Immutable block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Immutable block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Immutable block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Immutable block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Immutable block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Immutable:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Immutable:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Immutable node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/immutable/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/immutable/eth_syncing) - Check if node is still syncing

---

## eth_call - Immutable RPC Method

# eth_call - Immutable RPC Method

Executes a new message call immediately without creating a transaction on Immutable. Used for reading smart contract state.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

The `eth_call` method serves these key scenarios for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Immutable
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';
const walletAddress = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Immutable. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Immutable
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Immutable

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "data": "0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "data": "0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    data := common.FromHex("0x70a082310000000000000000000000003A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Immutable RPC Method

# eth_chainId - Immutable RPC Method

Returns the chain ID used for transaction signing on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_chainId` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/immutable/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/immutable/eth_syncing) - Check sync status

---

## eth_coinbase - Immutable RPC Method

# eth_coinbase - Immutable RPC Method

Checks the legacy `eth_coinbase` compatibility method on Immutable. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Immutable coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Immutable coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Immutable coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Immutable coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Immutable coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Immutable nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/immutable/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/immutable/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/immutable/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Immutable RPC Method

# eth_estimateGas - Immutable RPC Method

Estimates the gas necessary to execute a transaction on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Immutable
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Immutable.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Immutable may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "to": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/immutable/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Immutable RPC Method

# eth_feeHistory - Immutable RPC Method

Returns historical gas fee data on Immutable, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Immutable without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Immutable.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Immutable) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/immutable/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/immutable/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Immutable RPC Method

# eth_gasPrice - Immutable RPC Method

Returns the current gas price on Immutable in wei.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Immutable
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Immutable. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Immutable, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Immutable: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Immutable supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/immutable/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/immutable/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Immutable RPC Method

# eth_getBalance - Immutable RPC Method

Returns the balance of a given address on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getBalance` is fundamental for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Immutable
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Immutable
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Immutable. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Immutable`);
  return balance;
}

displayBalance('0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Immutable at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Immutable')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Immutable')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Immutable.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/immutable/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/immutable/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Immutable RPC Method

# eth_getBlockByHash - Immutable RPC Method

Returns information about a block by hash on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getBlockByHash` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Immutable
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Immutable.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Immutable.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Immutable RPC Method

# eth_getBlockByNumber - Immutable RPC Method

Returns information about a block by block number on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getBlockByNumber` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Immutable
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Immutable with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Immutable. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/immutable/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/immutable/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Immutable RPC Method

# eth_getBlockReceipts - Immutable RPC Method

Returns all transaction receipts for a block on Immutable. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getBlockReceipts` is useful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Immutable, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Immutable. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xdc3499901b5e089b0f67baeb512939f2949bf62cf1158e69bb458e7e43397136",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/immutable/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/immutable/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Immutable RPC Method

# eth_getCode - Immutable RPC Method

Returns the bytecode at a given address on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getCode` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Immutable
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Immutable:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Immutable:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/immutable/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/immutable/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Immutable RPC Method

# eth_getFilterChanges - Immutable RPC Method

Polls a filter on Immutable for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getFilterChanges` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Immutable
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Immutable:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/immutable/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/immutable/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/immutable/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/immutable/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/immutable/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Immutable RPC Method

# eth_getFilterLogs - Immutable RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Immutable. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getFilterLogs` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Immutable
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/immutable/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/immutable/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/immutable/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/immutable/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Immutable RPC Method

# eth_getLogs - Immutable RPC Method

Returns an array of all logs matching a given filter object on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Immutable for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Immutable
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Immutable.

```javascript
const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Immutable enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Immutable, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/immutable/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/immutable/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Immutable RPC Method

# eth_getStorageAt - Immutable RPC Method

Returns the value from a storage position at a given address on Immutable. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getStorageAt` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **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 Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **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": [
    "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "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-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D', '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-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';

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-immutable-zkevm-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 = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
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-immutable-zkevm-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-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    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 Immutable:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-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-immutable-zkevm-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 = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';
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 Immutable:`);
  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/immutable/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/immutable/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/immutable/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Immutable RPC Method

# eth_getTransactionByHash - Immutable RPC Method

Returns the information about a transaction by transaction hash on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getTransactionByHash` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Immutable
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Immutable. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Immutable. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/immutable/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Immutable RPC Method

# eth_getTransactionCount - Immutable RPC Method

Returns the number of transactions sent from an address on Immutable, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getTransactionCount` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Immutable
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Immutable nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D'
nonce = get_transaction_count(address)
print(f'Immutable nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Immutable nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Immutable:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/immutable/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/immutable/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/immutable/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Immutable RPC Method

# eth_getTransactionReceipt - Immutable RPC Method

Returns the receipt of a transaction by transaction hash on Immutable. Receipt is only available for mined transactions.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_getTransactionReceipt` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Immutable and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Immutable. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Immutable, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x63d1ef279d87a451bc017ca70614ea90270040a2e4b7fcadb1c6115ffcb29486")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/immutable/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/immutable/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Immutable RPC Method

# eth_hashrate - Immutable RPC Method

Returns the legacy `eth_hashrate` compatibility value on Immutable. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Immutable hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Immutable hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Immutable hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Immutable hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Immutable hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/immutable/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/immutable/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Immutable RPC Method

# eth_maxPriorityFeePerGas - Immutable RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Immutable. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Immutable
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Immutable priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Immutable priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Immutable priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Immutable:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Immutable:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/immutable/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/immutable/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/immutable/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Immutable RPC Method

# eth_mining - Immutable RPC Method

Checks the legacy `eth_mining` compatibility method on Immutable. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Immutable mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Immutable mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Immutable mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Immutable mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Immutable mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/immutable/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/immutable/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Immutable RPC Method

# eth_newBlockFilter - Immutable RPC Method

Creates a filter on Immutable that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_newBlockFilter` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Block Monitoring** - Detect new blocks on Immutable as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Immutable:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/immutable/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/immutable/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/immutable/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Immutable RPC Method

# eth_newFilter - Immutable RPC Method

Creates a filter object on Immutable based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_newFilter` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Event Monitoring** - Subscribe to specific contract events on Immutable such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Immutable:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/immutable/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/immutable/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/immutable/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/immutable/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/immutable/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Immutable RPC Method

# eth_newPendingTransactionFilter - Immutable RPC Method

Creates a filter on Immutable that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Mempool Monitoring** - Observe unconfirmed transactions on Immutable to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for Web3 gaming (Gods Unchained, RavenQuest), gaming NFTs with enforced royalties, and cross-chain game assets

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Immutable...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Immutable:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/immutable/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/immutable/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/immutable/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Immutable RPC Method

# eth_protocolVersion - Immutable RPC Method

Returns the current Ethereum protocol version used by the Immutable node.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_protocolVersion` is useful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Immutable protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Immutable protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Immutable protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Immutable protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Immutable protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Immutable nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/immutable/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/immutable/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/immutable/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Immutable RPC Method

# eth_sendRawTransaction - Immutable RPC Method

Submits a pre-signed transaction for broadcast to Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Immutable
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Immutable mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/immutable/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x3A0C2Ba54D6CBd3121f01b96DFd20e99D1696c9D")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/immutable/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/immutable/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Immutable RPC Method

# eth_sendTransaction - Immutable RPC Method

Creates and sends a new transaction from an unlocked account on Immutable. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Immutable tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Immutable tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Immutable tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Immutable tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Immutable tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Immutable dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/immutable/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/immutable/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Immutable RPC Method

# eth_signTransaction - Immutable RPC Method

Signs a transaction with the private key of the specified account on Immutable without submitting it to the network.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Immutable tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Immutable tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Immutable tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Immutable:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/immutable/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/immutable/eth_accounts) - List accounts available for signing

---

## eth_syncing - Immutable RPC Method

# eth_syncing - Immutable RPC Method

Returns the sync status of your Immutable node - either `false` when fully synced, or an object describing the sync progress.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_syncing` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Immutable node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Immutable node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Immutable node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/immutable/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/immutable/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/immutable/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Immutable RPC Method

# eth_uninstallFilter - Immutable RPC Method

Removes a filter on Immutable that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`eth_uninstallFilter` is important for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/immutable/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/immutable/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/immutable/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/immutable/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/immutable/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Immutable RPC Method

# net_listening - Immutable RPC Method

Checks whether the connected Immutable client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`net_listening` is useful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Immutable node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Immutable node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Immutable node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/immutable/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/immutable/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/immutable/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/immutable/web3_clientVersion) - Get node client info

---

## net_peerCount - Immutable RPC Method

# net_peerCount - Immutable RPC Method

Returns the number of peers currently connected to your Immutable node.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`net_peerCount` is important for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Immutable deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Immutable peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Immutable peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Immutable peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Immutable nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/immutable/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/immutable/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/immutable/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/immutable/web3_clientVersion) - Get node client info

---

## net_version - Immutable RPC Method

# net_version - Immutable RPC Method

Returns the current network ID on Immutable as a decimal string. The network ID identifies which network the node is connected to.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`net_version` is essential for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Endpoint Identification** - Confirm your application is connected to the expected Immutable network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Immutable network ID:', networkId);

// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Immutable network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Immutable network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/immutable/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/immutable/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/immutable/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/immutable/eth_syncing) - Check node sync progress

---

## rpc_modules - Immutable RPC Method

# rpc_modules - Immutable RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Immutable endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`rpc_modules` is useful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/immutable/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/immutable/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Immutable RPC Method

# txpool_content - Immutable RPC Method

Returns the full pending and queued transaction pool for the connected Immutable endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`txpool_content` is useful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/immutable/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/immutable/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/immutable/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Immutable RPC Method

# txpool_status - Immutable RPC Method

Returns transaction pool counters for the connected Immutable endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`txpool_status` is valuable for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/immutable/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/immutable/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/immutable/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Immutable RPC Method

# web3_clientVersion - Immutable RPC Method

Returns the current client software version string for your Immutable node, including the client name, version number, OS, and runtime.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

## When to Use This Method

`web3_clientVersion` is valuable for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Immutable client:', clientVersion);

// Using fetch
const response = await fetch('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Immutable client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Immutable client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/immutable/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/immutable/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/immutable/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/immutable/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Immutable RPC Method

# web3_sha3 - Immutable RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Immutable.

> **Why Immutable?** Build on the gaming-optimized zkEVM with 660+ games, 5.5M+ Passport signups, and $40M TVL with first EVM chain with enforceable royalties, Polygon zkEVM technology, $2B+ ecosystem funding, and Agglayer cross-chain liquidity.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for AAA game studios, indie game developers, and NFT gaming teams seeking enforceable royalties:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-immutable-zkevm-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/immutable/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/immutable/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/immutable/web3_clientVersion) - Get node client version

---

## Ink RPC and API Documentation

# Ink RPC and API Documentation

## Ink RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Ink supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Ink?

Ink is an Ethereum Layer 2 built on the OP Stack and designed as a DeFi-focused home in the Optimism Superchain. It uses ETH for gas, supports standard EVM tooling, and gives Solidity developers a familiar path to deploy low-fee applications with fast confirmations.

### **DeFi-First L2**

- **Built for DeFi** - Designed for liquidity, trading, and onchain financial applications
- **Kraken-backed ecosystem** - Launched by Kraken with builder support and DeFi distribution in mind
- **Superchain alignment** - Built on the OP Stack for Optimism ecosystem interoperability

### **EVM-Compatible Infrastructure**

- **Standard JSON-RPC** - Use Ethereum RPC methods with existing tools and SDKs
- **Solidity support** - Deploy contracts built for Ethereum and other EVM L2s
- **ETH gas** - Keep familiar wallet and fee flows for users

### **Fast, Low-Fee Execution**

- **Chain ID 57073** - Ink mainnet
- **Fast blocks** - 1 second block times at launch
- **Lower fees** - OP Stack scaling with Ethereum settlement

## Quick Start with Ink

## Network Specifications

| Parameter | Value                                                       | Details             |
| --------- | ----------------------------------------------------------- | ------------------- |
| Chain ID  | 57073                                                       | Mainnet             |
| Currency  | ETH                                                         | Native gas token    |
| Stack     | OP Stack                                                    | Optimism Superchain |
| Explorer  | [explorer.inkonchain.com](https://explorer.inkonchain.com/) | Mainnet explorer    |

## API Methods

### Core Ethereum Methods

Ink supports standard Ethereum JSON-RPC methods:

- Transaction methods (`eth_sendRawTransaction`, `eth_getTransactionReceipt`)
- Block methods (`eth_getBlockByNumber`, `eth_blockNumber`)
- Account methods (`eth_getBalance`, `eth_getCode`)
- Event methods (`eth_getLogs`, `eth_newFilter`)

### Debug & Trace Methods

Dwellir's Ink endpoint exposes reth-backed debug and trace namespaces:

- `debug_traceTransaction` - Inspect transaction execution
- `debug_traceBlockByNumber` - Trace full blocks
- `trace_call` and `trace_filter` - Parity-style tracing workflows

## Developer Resources

### Ethers.js Example

```javascript
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider(
  'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const network = await provider.getNetwork();
console.log('Connected to Ink:', network.chainId === 57073n);

const blockNumber = await provider.getBlockNumber();
console.log('Latest Ink block:', blockNumber);
```

### viem Example

```typescript
import { createPublicClient, http } from 'viem';
import { defineChain } from 'viem';

const ink = defineChain({
  id: 57073,
  name: 'Ink',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: {
    default: {
      http: ['https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
});

const client = createPublicClient({
  chain: ink,
  transport: http(),
});

const blockNumber = await client.getBlockNumber();
```

## Resources & Support

- **Official Docs**: [Ink documentation](https://docs.inkonchain.com/)
- **Explorer**: [Ink Explorer](https://explorer.inkonchain.com/)
- **Status**: [Ink Status](https://status.inkonchain.com/)
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

---

## debug_traceBlock - Ink RPC Method

# debug_traceBlock - Ink RPC Method

Traces all transactions in a block on Ink by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ink - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Ink
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Ink:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Ink blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ink/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ink/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ink/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ink/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Ink RPC Method

# debug_traceBlockByHash - Ink RPC Method

Traces all transactions in a block on Ink identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ink - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Ink
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Ink:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Ink:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/ink/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ink/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ink/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ink/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ink/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Ink RPC Method

# debug_traceBlockByNumber - Ink RPC Method

Traces all transactions in a block on Ink identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ink - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Ink execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Ink:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Ink:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/ink/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ink/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ink/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ink/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Ink RPC Method

# debug_traceCall - Ink RPC Method

Traces a call on Ink without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Ink - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Ink
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Ink to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Ink:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Ink:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/ink/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ink/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ink/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ink/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Ink RPC Method

# debug_traceTransaction - Ink RPC Method

Traces a transaction execution on Ink by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Ink
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/ink/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ink/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Ink RPC Method

# eth_accounts - Ink RPC Method

Returns a list of addresses owned by the client on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/ink/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/ink/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Ink RPC Method

# eth_blockNumber - Ink RPC Method

Returns the number of the most recent block on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_blockNumber` is fundamental for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Syncing Applications** - Keep your dApp in sync with the latest Ink blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Ink block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Ink block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Ink block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Ink block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ink block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Ink:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Ink:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Ink node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ink/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/ink/eth_syncing) - Check if node is still syncing

---

## eth_call - Ink RPC Method

# eth_call - Ink RPC Method

Executes a new message call immediately without creating a transaction on Ink. Used for reading smart contract state.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

The `eth_call` method serves these key scenarios for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Ink
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Ink. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Ink
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Ink

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Ink RPC Method

# eth_chainId - Ink RPC Method

Returns the chain ID used for transaction signing on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_chainId` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/ink/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/ink/eth_syncing) - Check sync status

---

## eth_coinbase - Ink RPC Method

# eth_coinbase - Ink RPC Method

Checks the legacy `eth_coinbase` compatibility method on Ink. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Ink coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Ink coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Ink coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ink coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Ink coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Ink nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/ink/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/ink/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/ink/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Ink RPC Method

# eth_estimateGas - Ink RPC Method

Estimates the gas necessary to execute a transaction on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Ink
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Ink.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Ink may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ink/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Ink RPC Method

# eth_feeHistory - Ink RPC Method

Returns historical gas fee data on Ink, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Ink without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Ink.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Ink) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ink/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/ink/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Ink RPC Method

# eth_gasPrice - Ink RPC Method

Returns the current gas price on Ink in wei.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Ink
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Ink. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Ink, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Ink: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Ink supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/ink/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/ink/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Ink RPC Method

# eth_getBalance - Ink RPC Method

Returns the balance of a given address on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getBalance` is fundamental for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Ink
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Ink
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Ink. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Ink`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Ink at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Ink')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Ink')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Ink.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/ink/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/ink/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Ink RPC Method

# eth_getBlockByHash - Ink RPC Method

Returns information about a block by hash on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getBlockByHash` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Ink
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Ink.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Ink.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Ink RPC Method

# eth_getBlockByNumber - Ink RPC Method

Returns information about a block by block number on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getBlockByNumber` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Ink
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Ink with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Ink. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ink/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ink/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Ink RPC Method

# eth_getBlockReceipts - Ink RPC Method

Returns all transaction receipts for a block on Ink. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getBlockReceipts` is useful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Ink, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Ink. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x4da3692d55759ca2fa35e8093aaedf76b1075e5c2d6346365e318c153f0327db",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ink/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ink/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Ink RPC Method

# eth_getCode - Ink RPC Method

Returns the bytecode at a given address on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getCode` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Ink
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Ink:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Ink:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/ink/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/ink/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Ink RPC Method

# eth_getFilterChanges - Ink RPC Method

Polls a filter on Ink for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getFilterChanges` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Ink
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Ink:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ink/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ink/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ink/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ink/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/ink/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Ink RPC Method

# eth_getFilterLogs - Ink RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Ink. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getFilterLogs` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Ink
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ink/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ink/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/ink/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ink/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Ink RPC Method

# eth_getLogs - Ink RPC Method

Returns an array of all logs matching a given filter object on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Ink for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Ink
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Ink.

```javascript
const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Ink enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Ink, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ink/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ink/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Ink RPC Method

# eth_getStorageAt - Ink RPC Method

Returns the value from a storage position at a given address on Ink. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getStorageAt` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **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 low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-ink-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 = '0x4200000000000000000000000000000000000006'
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-ink-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-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 Ink:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-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-ink-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 = '0x4200000000000000000000000000000000000006';
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 Ink:`);
  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/ink/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/ink/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/ink/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Ink RPC Method

# eth_getTransactionByHash - Ink RPC Method

Returns the information about a transaction by transaction hash on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getTransactionByHash` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Ink
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Ink. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Ink. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ink/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Ink RPC Method

# eth_getTransactionCount - Ink RPC Method

Returns the number of transactions sent from an address on Ink, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getTransactionCount` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Ink
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Ink nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'Ink nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Ink nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Ink:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/ink/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ink/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ink/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Ink RPC Method

# eth_getTransactionReceipt - Ink RPC Method

Returns the receipt of a transaction by transaction hash on Ink. Receipt is only available for mined transactions.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_getTransactionReceipt` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Ink and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Ink. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Ink, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ink/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/ink/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Ink RPC Method

# eth_hashrate - Ink RPC Method

Returns the legacy `eth_hashrate` compatibility value on Ink. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Ink hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Ink hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Ink hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ink hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Ink hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/ink/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/ink/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Ink RPC Method

# eth_maxPriorityFeePerGas - Ink RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Ink. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Ink
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Ink priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Ink priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Ink priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Ink:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Ink:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ink/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/ink/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ink/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Ink RPC Method

# eth_mining - Ink RPC Method

Checks the legacy `eth_mining` compatibility method on Ink. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Ink mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Ink mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Ink mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ink mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Ink mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/ink/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/ink/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Ink RPC Method

# eth_newBlockFilter - Ink RPC Method

Creates a filter on Ink that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_newBlockFilter` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Block Monitoring** - Detect new blocks on Ink as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Ink:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ink/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ink/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ink/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Ink RPC Method

# eth_newFilter - Ink RPC Method

Creates a filter object on Ink based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_newFilter` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Event Monitoring** - Subscribe to specific contract events on Ink such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Ink:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ink/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ink/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/ink/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ink/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ink/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Ink RPC Method

# eth_newPendingTransactionFilter - Ink RPC Method

Creates a filter on Ink that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Mempool Monitoring** - Observe unconfirmed transactions on Ink to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Ink...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Ink:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ink/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ink/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ink/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Ink RPC Method

# eth_protocolVersion - Ink RPC Method

Returns the current Ethereum protocol version used by the Ink node.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_protocolVersion` is useful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Ink protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Ink protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Ink protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Ink protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ink protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Ink nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/ink/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/ink/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/ink/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Ink RPC Method

# eth_sendRawTransaction - Ink RPC Method

Submits a pre-signed transaction for broadcast to Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Ink
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Ink mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/ink/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/ink/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ink/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Ink RPC Method

# eth_sendTransaction - Ink RPC Method

Creates and sends a new transaction from an unlocked account on Ink. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Ink tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Ink tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Ink tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Ink tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ink tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Ink dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/ink/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/ink/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Ink RPC Method

# eth_signTransaction - Ink RPC Method

Signs a transaction with the private key of the specified account on Ink without submitting it to the network.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Ink tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Ink tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Ink tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Ink:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/ink/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/ink/eth_accounts) - List accounts available for signing

---

## eth_syncing - Ink RPC Method

# eth_syncing - Ink RPC Method

Returns the sync status of your Ink node - either `false` when fully synced, or an object describing the sync progress.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_syncing` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Ink node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Ink node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Ink node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/ink/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/ink/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/ink/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Ink RPC Method

# eth_uninstallFilter - Ink RPC Method

Removes a filter on Ink that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`eth_uninstallFilter` is important for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ink/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ink/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/ink/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ink/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ink/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Ink RPC Method

# net_listening - Ink RPC Method

Checks whether the connected Ink client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`net_listening` is useful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Ink node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Ink node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Ink node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/ink/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/ink/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ink/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/ink/web3_clientVersion) - Get node client info

---

## net_peerCount - Ink RPC Method

# net_peerCount - Ink RPC Method

Returns the number of peers currently connected to your Ink node.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`net_peerCount` is important for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Ink deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Ink peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Ink peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Ink peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Ink nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/ink/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/ink/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ink/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/ink/web3_clientVersion) - Get node client info

---

## net_version - Ink RPC Method

# net_version - Ink RPC Method

Returns the current network ID on Ink as a decimal string. The network ID identifies which network the node is connected to.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`net_version` is essential for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Endpoint Identification** - Confirm your application is connected to the expected Ink network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Ink network ID:', networkId);

// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Ink network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ink network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/ink/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/ink/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/ink/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/ink/eth_syncing) - Check node sync progress

---

## rpc_modules - Ink RPC Method

# rpc_modules - Ink RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Ink endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`rpc_modules` is useful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/ink/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ink/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/ink/trace_transaction) - Trace namespace example

---

## trace_block - Ink RPC Method

# trace_block - Ink RPC Method

Returns traces for all transactions in a block on Ink.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Ink
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Ink chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/ink/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/ink/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/ink/trace_get) - Get a specific trace by index

---

## trace_call - Ink RPC Method

# trace_call - Ink RPC Method

Traces a call without creating a transaction on Ink, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Ink
- **Pre-execution analysis** - Test contract interactions without spending gas for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x4200000000000000000000000000000000000006", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x4200000000000000000000000000000000000006',
        'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/ink/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/ink/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/ink/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Ink RPC Method

# trace_callMany - Ink RPC Method

Traces multiple calls in sequence on Ink, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Ink
- **Historical state comparison** - Compare how the same call would execute at different points in Ink chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x4200000000000000000000000000000000000006", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"}, ["trace"]],
      [{"to": "0x4200000000000000000000000000000000000006", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x4200000000000000000000000000000000000006", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"}, ["trace"]],
        [{"to": "0x4200000000000000000000000000000000000006", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x4200000000000000000000000000000000000006', data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006' }, ['trace']],
    [{ to: '0x4200000000000000000000000000000000000006', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x4200000000000000000000000000000000000006', 'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'}, ['trace']],
        [{'to': '0x4200000000000000000000000000000000000006', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/ink/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/ink/eth_call) - Execute call without trace

---

## trace_filter - Ink RPC Method

# trace_filter - Ink RPC Method

Returns traces matching a filter on Ink.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Ink
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x4200000000000000000000000000000000000006"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x4200000000000000000000000000000000000006"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x4200000000000000000000000000000000000006'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x4200000000000000000000000000000000000006'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/ink/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/ink/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/ink/eth_getLogs) - Filter event logs

---

## trace_get - Ink RPC Method

# trace_get - Ink RPC Method

Returns a trace at a specific position within a transaction on Ink.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Ink
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/ink/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/ink/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Ink RPC Method

# trace_replayBlockTransactions - Ink RPC Method

Replays all transactions in a block on Ink and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Ink
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Ink chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/ink/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/ink/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/ink/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Ink RPC Method

# trace_replayTransaction - Ink RPC Method

Replays a transaction on Ink and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Ink
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/ink/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/ink/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/ink/trace_block) - Get all traces in a block

---

## trace_transaction - Ink RPC Method

# trace_transaction - Ink RPC Method

Returns all traces for a specific transaction on Ink.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for low-fee DeFi applications, cross-chain liquidity, and EVM-compatible smart contracts
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Ink
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x17d1ffb71c72ff3a382b13a1ced2218313e334b36a6c8f5917b743e4b4436a9b'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/ink/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/ink/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/ink/trace_filter) - Filter traces by criteria

---

## txpool_content - Ink RPC Method

# txpool_content - Ink RPC Method

Returns the full pending and queued transaction pool for the connected Ink endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`txpool_content` is useful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/ink/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ink/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ink/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Ink RPC Method

# txpool_status - Ink RPC Method

Returns transaction pool counters for the connected Ink endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`txpool_status` is valuable for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/ink/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/ink/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/ink/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Ink RPC Method

# web3_clientVersion - Ink RPC Method

Returns the current client software version string for your Ink node, including the client name, version number, OS, and runtime.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

## When to Use This Method

`web3_clientVersion` is valuable for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Ink client:', clientVersion);

// Using fetch
const response = await fetch('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Ink client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ink client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/ink/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ink/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/ink/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/ink/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Ink RPC Method

# web3_sha3 - Ink RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Ink.

> **Why Ink?** Build on Kraken's DeFi-focused Ethereum L2 built on the OP Stack and connected to the Optimism Superchain with 1s block times, ETH gas, Kraken-backed infrastructure, OP Stack compatibility, and Superchain interoperability.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for Ink developers, DeFi builders, and teams deploying Solidity applications on the Superchain:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-ink-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/ink/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/ink/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/ink/web3_clientVersion) - Get node client version

---

## IoTeX - The Leading Blockchain for IoT and DePIN

# IoTeX - The Leading Blockchain for IoT and DePIN

## IoTeX RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where IoTeX supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on IoTeX?

IoTeX is the leading blockchain platform for Internet of Things (IoT) and Decentralized Physical Infrastructure Networks (DePIN). Purpose-built for connecting the physical and digital worlds, IoTeX offers:

### **IoT & Machine Integration**

- **Native device connectivity** - Direct integration with billions of IoT devices
- **W3bstream** - Off-chain compute for real-world data processing
- **MachineFi** - Financialize machine resources and data
- **Trusted IoT data** - Verifiable proofs for device-generated data

### **High Performance Infrastructure**

- **5-second block time** - Fast finality for real-time applications
- **Ultra-low fees** - Optimized for high-frequency IoT transactions
- **10,000+ TPS** - Scale for billions of device interactions
- **EVM compatibility** - Deploy existing Ethereum dApps instantly

### **Privacy & Security**

- **Roll-DPoS consensus** - Randomized delegated proof-of-stake
- **Trusted Execution Environment** - Secure computation for sensitive data
- **Privacy-preserving computation** - Process data without exposure
- **Device identity** - Decentralized identity for IoT devices

### **DePIN Ecosystem Leader**

- **$3B+ market cap** - Top DePIN infrastructure blockchain
- **100+ DePIN projects** - Largest decentralized infrastructure ecosystem
- **Real-world assets** - Tokenize and trade physical infrastructure
- **Global device network** - Connected devices across 70+ countries

## Quick Start with IoTeX

Connect to IoTeX in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to IoTeX mainnet
const provider = new JsonRpcProvider(
  'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query IOTX balance
const balance = await provider.getBalance('0x...');
console.log('IOTX Balance:', balance.toString());

// Interact with IoT device registry
const deviceRegistry = new Contract(registryAddress, abi, provider);
const deviceData = await deviceRegistry.getDeviceData('device_id');
```

```javascript
const Web3 = require('web3');

// Connect to IoTeX mainnet
const web3 = new Web3(
  'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Verify connection to IoTeX (Chain ID: 4689)
const chainId = await web3.eth.getChainId();
console.log('Connected to IoTeX:', chainId === 4689);

// Get gas price optimized for IoT transactions
const gasPrice = await web3.eth.getGasPrice();
console.log('IoT-optimized gas price:', gasPrice);

// Read IoT sensor data from smart contract
const sensorContract = new web3.eth.Contract(abi, contractAddress);
const data = await sensorContract.methods.getLatestReading().call();
```

```typescript
import { createPublicClient, http, defineChain } from 'viem';

// Define IoTeX chain
const iotex = defineChain({
  id: 4689,
  name: 'IoTeX',
  network: 'iotex',
  nativeCurrency: {
    decimals: 18,
    name: 'IoTeX',
    symbol: 'IOTX',
  },
  rpcUrls: {
    default: {
      http: ['https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
  blockExplorers: {
    default: { name: 'IoTeXScan', url: 'https://iotexscan.io' },
  },
});

// Create IoTeX client
const client = createPublicClient({
  chain: iotex,
  transport: http(),
});

// Read IoT device data
const deviceStatus = await client.readContract({
  address: '0x...',
  abi: deviceAbi,
  functionName: 'getDeviceStatus',
  args: ['device_001'],
});
```

## Network Information

| Parameter  | Value     | Details         |
| ---------- | --------- | --------------- |
| Chain ID   | 4689      | Mainnet         |
| Block Time | 5 seconds | Average         |
| Gas Token  | IOTX      | Native token    |
| Consensus  | Roll-DPoS | Randomized DPoS |

## API Reference

IoTeX supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) plus custom methods for IoT and DePIN functionality. Access all standard EVM methods for seamless integration.

## IoT & DePIN Integration Patterns

### Device Registration & Management

Register and manage IoT devices on-chain:

```javascript
// Device registration contract
const DeviceRegistry = {
  // Register new IoT device
  async registerDevice(deviceId, metadata) {
    const tx = await contract.registerDevice(
      deviceId,
      metadata.manufacturer,
      metadata.model,
      metadata.location,
      { gasLimit: 100000 }
    );
    return tx.wait();
  },

  // Update device status
  async updateDeviceStatus(deviceId, status, timestamp) {
    const signature = await signDeviceData(deviceId, status, timestamp);
    return contract.updateStatus(deviceId, status, timestamp, signature);
  },

  // Query device history
  async getDeviceHistory(deviceId, fromBlock = 0) {
    const filter = contract.filters.DeviceUpdate(deviceId);
    return contract.queryFilter(filter, fromBlock);
  }
};
```

### W3bstream Data Processing

Process IoT data off-chain with verifiable proofs:

```javascript
// W3bstream integration for IoT data
class W3bstreamProcessor {
  constructor(endpoint) {
    this.endpoint = endpoint;
    this.provider = new JsonRpcProvider(
      'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'
    );
  }

  // Submit IoT data for processing
  async submitData(deviceId, data) {
    // Create data proof
    const proof = await this.createProof(deviceId, data);

    // Submit to W3bstream
    const result = await fetch(`${this.endpoint}/submit`, {
      method: 'POST',
      body: JSON.stringify({
        deviceId,
        data,
        proof,
        timestamp: Date.now()
      })
    });

    // Store proof on-chain
    const tx = await this.storeProof(proof);
    return { proofId: tx.hash, result: await result.json() };
  }

  // Verify data authenticity
  async verifyData(proofId) {
    const proof = await this.contract.getProof(proofId);
    return this.verifyProof(proof);
  }
}
```

### DePIN Infrastructure

Build decentralized physical infrastructure:

```javascript
// DePIN node management
const DePINManager = {
  // Register infrastructure node
  async registerNode(nodeInfo) {
    const stake = ethers.parseEther('1000'); // Minimum stake

    const tx = await contract.registerNode(
      nodeInfo.id,
      nodeInfo.type, // 'sensor', 'gateway', 'compute'
      nodeInfo.location,
      nodeInfo.capabilities,
      { value: stake }
    );

    return tx.wait();
  },

  // Submit proof of work
  async submitProofOfWork(nodeId, data) {
    const proof = await generateWorkProof(nodeId, data);
    return contract.submitProof(nodeId, proof);
  },

  // Claim rewards
  async claimRewards(nodeId) {
    const rewards = await contract.pendingRewards(nodeId);
    if (rewards > 0) {
      return contract.claimRewards(nodeId);
    }
  }
};
```

## Performance Best Practices

### 1. **Batch IoT Data Submissions**

Optimize for high-frequency sensor data:

```javascript
class BatchProcessor {
  constructor() {
    this.batch = [];
    this.batchSize = 100;
  }

  async addReading(deviceId, data) {
    this.batch.push({ deviceId, data, timestamp: Date.now() });

    if (this.batch.length >= this.batchSize) {
      await this.submitBatch();
    }
  }

  async submitBatch() {
    if (this.batch.length === 0) return;

    const merkleRoot = this.calculateMerkleRoot(this.batch);

    // Submit only merkle root on-chain
    const tx = await contract.submitBatch(
      merkleRoot,
      this.batch.length,
      { gasLimit: 200000 }
    );

    // Store full data off-chain
    await this.storeOffchain(this.batch, tx.hash);

    this.batch = [];
    return tx;
  }
}
```

### 2. **Device Connection Pooling**

Manage multiple IoT device connections efficiently:

```javascript
class DeviceConnectionPool {
  constructor(maxConnections = 100) {
    this.pool = new Map();
    this.maxConnections = maxConnections;
  }

  async getConnection(deviceId) {
    if (!this.pool.has(deviceId)) {
      if (this.pool.size >= this.maxConnections) {
        this.evictOldest();
      }

      const connection = await this.createConnection(deviceId);
      this.pool.set(deviceId, {
        connection,
        lastUsed: Date.now()
      });
    }

    const poolEntry = this.pool.get(deviceId);
    poolEntry.lastUsed = Date.now();
    return poolEntry.connection;
  }

  evictOldest() {
    let oldest = Date.now();
    let oldestId = null;

    for (const [id, entry] of this.pool.entries()) {
      if (entry.lastUsed < oldest) {
        oldest = entry.lastUsed;
        oldestId = id;
      }
    }

    if (oldestId) {
      this.pool.delete(oldestId);
    }
  }
}
```

### 3. **Efficient Event Monitoring**

Monitor device events with minimal overhead:

```javascript
class EventMonitor {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async watchDevice(deviceId, callback) {
    // Create optimized filter
    const filter = {
      address: CONTRACT_ADDRESS,
      topics: [
        ethers.id('DeviceUpdate(string,uint256,bytes32)'),
        ethers.id(deviceId)
      ]
    };

    // Use WebSocket for real-time updates
    this.provider.on(filter, async (log) => {
      const parsed = this.parseLog(log);
      await callback(parsed);
    });

    this.filters.set(deviceId, filter);
  }

  stopWatching(deviceId) {
    const filter = this.filters.get(deviceId);
    if (filter) {
      this.provider.off(filter);
      this.filters.delete(deviceId);
    }
  }
}
```

## Troubleshooting Common Issues

### Error: "Device not registered"

Ensure IoT devices are properly registered before submitting data:

```javascript
async function ensureDeviceRegistered(deviceId) {
  try {
    const device = await contract.getDevice(deviceId);
    return device.isActive;
  } catch (error) {
    if (error.message.includes('Device not found')) {
      // Auto-register device
      await contract.registerDevice(
        deviceId,
        DEFAULT_METADATA,
        { gasLimit: 150000 }
      );
      return true;
    }
    throw error;
  }
}
```

### Error: "Invalid sensor data format"

Validate IoT data before submission:

```javascript
function validateSensorData(data) {
  const required = ['deviceId', 'timestamp', 'value'];

  for (const field of required) {
    if (!data[field]) {
      throw new Error(`Missing required field: ${field}`);
    }
  }

  // Validate timestamp is recent (within 5 minutes)
  const fiveMinutes = 5 * 60 * 1000;
  if (Date.now() - data.timestamp > fiveMinutes) {
    throw new Error('Timestamp too old');
  }

  // Validate value ranges
  if (data.value < MIN_VALUE || data.value > MAX_VALUE) {
    throw new Error('Value out of range');
  }

  return true;
}
```

### Error: "W3bstream proof verification failed"

Handle W3bstream proof errors:

```javascript
async function submitWithRetry(data, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const proof = await w3bstream.generateProof(data);
      const tx = await contract.submitProof(proof);
      return tx;
    } catch (error) {
      if (error.message.includes('proof verification')) {
        // Regenerate proof with fresh nonce
        data.nonce = Date.now();
        continue;
      }
      throw error;
    }
  }
  throw new Error('Failed to submit proof after retries');
}
```

## Migration Guide

### From Ethereum/EVM Chains

IoTeX is fully EVM-compatible with additional IoT features:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-mainnet.example.com');
const contract = new Contract(address, abi, provider);

// After (IoTeX)
const provider = new JsonRpcProvider(
  'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'
);
const contract = new Contract(address, abi, provider);

// All Ethereum tools work
// Same development workflow
// Additional IoT capabilities
// Note: Different chain ID (4689)
// Note: IOTX as gas token (not ETH)
// Access to W3bstream and MachineFi
```

### Integrating IoT Devices

Connect physical devices to IoTeX:

```javascript
// Device SDK integration
import { IoTeXDevice } from '@iotex/device-sdk';

const device = new IoTeXDevice({
  deviceId: 'sensor_001',
  privateKey: process.env.DEVICE_KEY,
  endpoint: 'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'
});

// Auto-submit sensor readings
device.on('reading', async (data) => {
  await device.submitToBlockchain(data);
});

// Start monitoring
device.startMonitoring({
  interval: 60000, // Every minute
  sensors: ['temperature', 'humidity']
});
```

## Resources & Tools

### Official Resources

- [IoTeX Documentation](https://docs.iotex.io)
- [IoTeX Explorer](https://iotexscan.io)
- [W3bstream Docs](https://docs.w3bstream.com)

### Developer Tools

- [IoTeX Developer Portal](https://developers.iotex.io/)
- [IoTeX GitHub](https://github.com/iotexproject)
- [IoTeX Core](https://github.com/iotexproject/iotex-core)

### DePIN Resources

- [DePINscan Explorer](https://depinscan.io)
- [MachineFi Portal](https://machinefi.com)
- [IoTeX DePIN Guide](https://docs.iotex.io/depin)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building IoT and DePIN applications on IoTeX with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - IoTeX RPC Method

# debug_traceBlock - IoTeX RPC Method

Traces all transactions in a block on IoTeX by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **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.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for IoTeX - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on IoTeX
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## 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": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on IoTeX:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in IoTeX blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/iotex/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/iotex/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/iotex/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/iotex/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - IoTeX RPC Method

# debug_traceBlockByHash - IoTeX RPC Method

Traces all transactions in a block on IoTeX identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **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.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for IoTeX - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on IoTeX
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on IoTeX:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on IoTeX:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/iotex/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/iotex/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/iotex/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/iotex/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/iotex/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - IoTeX RPC Method

# debug_traceBlockByNumber - IoTeX RPC Method

Traces all transactions in a block on IoTeX identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **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.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for IoTeX - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of IoTeX execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on IoTeX:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on IoTeX:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/iotex/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/iotex/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/iotex/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/iotex/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - IoTeX RPC Method

# debug_traceCall - IoTeX RPC Method

Traces a call on IoTeX without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **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.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for IoTeX - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on IoTeX
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "data": "0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
        "data": "0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
        "data": "0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    data: '0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    data: '0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    'data': '0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xA00744882684C3e4747fAEFd68D283eA44099D03",
        "data": "0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on IoTeX to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on IoTeX:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on IoTeX:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/iotex/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/iotex/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/iotex/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/iotex/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - IoTeX RPC Method

# debug_traceTransaction - IoTeX RPC Method

Traces a transaction execution on IoTeX by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on IoTeX
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/iotex/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/iotex/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - IoTeX RPC Method

# eth_accounts - IoTeX RPC Method

Returns a list of addresses owned by the client on IoTeX.

> **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.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DePIN builders, IoT device manufacturers, and real-world AI application developers in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## 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_accounts",
    "params": [],
    "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_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/iotex/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/iotex/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - IoTeX RPC Method

# eth_blockNumber - IoTeX RPC Method

Returns the number of the most recent block on IoTeX.

> **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_blockNumber` is fundamental for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Syncing Applications** - Keep your dApp in sync with the latest IoTeX blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## 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_blockNumber",
    "params": [],
    "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_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('IoTeX block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('IoTeX block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'IoTeX block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'IoTeX block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("IoTeX block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on IoTeX:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on IoTeX:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your IoTeX node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/iotex/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/iotex/eth_syncing) - Check if node is still syncing

---

## eth_call - IoTeX RPC Method

# eth_call - IoTeX RPC Method

Executes a new message call immediately without creating a transaction on IoTeX. Used for reading smart contract state.

> **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

The `eth_call` method serves these key scenarios for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on IoTeX
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';
const walletAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on IoTeX. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on IoTeX
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on IoTeX

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "data": "0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "data": "0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    '0xA00744882684C3e4747fAEFd68D283eA44099D03'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "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)
    }

    contractAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    data := common.FromHex("0x70a08231000000000000000000000000A00744882684C3e4747fAEFd68D283eA44099D03")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - IoTeX RPC Method

# eth_chainId - IoTeX RPC Method

Returns the chain ID used for transaction signing on IoTeX.

> **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_chainId` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## 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_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/iotex/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/iotex/eth_syncing) - Check sync status

---

## eth_coinbase - IoTeX RPC Method

# eth_coinbase - IoTeX RPC Method

Checks the legacy `eth_coinbase` compatibility method on IoTeX. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **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.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DePIN builders, IoT device manufacturers, and real-world AI application developers when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## 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_coinbase",
    "params": [],
    "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_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('IoTeX coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('IoTeX coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'IoTeX coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'IoTeX coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("IoTeX coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of IoTeX nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/iotex/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/iotex/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/iotex/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - IoTeX RPC Method

# eth_estimateGas - IoTeX RPC Method

Estimates the gas necessary to execute a transaction on IoTeX.

> **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

The `eth_estimateGas` method serves these key scenarios for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on IoTeX
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xA00744882684C3e4747fAEFd68D283eA44099D03', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xA00744882684C3e4747fAEFd68D283eA44099D03', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on IoTeX.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like IoTeX may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## 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_estimateGas",
    "params": [{
      "from": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "to": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xA00744882684C3e4747fAEFd68D283eA44099D03', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "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)
    }

    toAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/iotex/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - IoTeX RPC Method

# eth_feeHistory - IoTeX RPC Method

Returns historical gas fee data on IoTeX, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **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

The `eth_feeHistory` method serves these key scenarios for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on IoTeX without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on IoTeX.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on IoTeX) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## 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_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "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_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "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)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/iotex/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/iotex/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - IoTeX RPC Method

# eth_gasPrice - IoTeX RPC Method

Returns the current gas price on IoTeX in wei.

> **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

The `eth_gasPrice` method serves these key scenarios for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on IoTeX
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of IoTeX. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on IoTeX, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on IoTeX: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if IoTeX supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## 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_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "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)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/iotex/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/iotex/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - IoTeX RPC Method

# eth_getBalance - IoTeX RPC Method

Returns the balance of a given address on IoTeX.

> **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_getBalance` is fundamental for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Wallet applications**: Display user balances and enable balance-dependent operations on IoTeX
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to IoTeX
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on IoTeX. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} IoTeX`);
  return balance;
}

displayBalance('0xA00744882684C3e4747fAEFd68D283eA44099D03');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on IoTeX at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xA00744882684C3e4747fAEFd68D283eA44099D03'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 IoTeX')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 IoTeX')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on IoTeX.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## 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_getBalance",
    "params": [
      "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xA00744882684C3e4747fAEFd68D283eA44099D03';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xA00744882684C3e4747fAEFd68D283eA44099D03'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/iotex/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/iotex/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - IoTeX RPC Method

# eth_getBlockByHash - IoTeX RPC Method

Returns information about a block by hash on IoTeX.

> **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_getBlockByHash` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on IoTeX
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on IoTeX.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on IoTeX.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## 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_getBlockByHash",
    "params": [
      "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    blockHash := common.HexToHash("0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/iotex/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - IoTeX RPC Method

# eth_getBlockByNumber - IoTeX RPC Method

Returns information about a block by block number on IoTeX.

> **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_getBlockByNumber` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on IoTeX
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on IoTeX with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on IoTeX. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## 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_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "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)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/iotex/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/iotex/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/iotex/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - IoTeX RPC Method

# eth_getBlockReceipts - IoTeX RPC Method

Returns all transaction receipts for a block on IoTeX. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **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_getBlockReceipts` is useful for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for IoTeX, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on IoTeX. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## 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_getBlockReceipts",
    "params": ["0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/iotex/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/iotex/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - IoTeX RPC Method

# eth_getCode - IoTeX RPC Method

Returns the bytecode at a given address on IoTeX.

> **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_getCode` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on IoTeX
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on IoTeX:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on IoTeX:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## 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_getCode",
    "params": [
      "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xA00744882684C3e4747fAEFd68D283eA44099D03';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xA00744882684C3e4747fAEFd68D283eA44099D03'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/iotex/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/iotex/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - IoTeX RPC Method

# eth_getFilterChanges - IoTeX RPC Method

Polls a filter on IoTeX for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **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_getFilterChanges` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on IoTeX
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## 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_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xA00744882684C3e4747fAEFd68D283eA44099D03'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "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)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on IoTeX:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/iotex/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/iotex/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/iotex/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/iotex/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/iotex/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - IoTeX RPC Method

# eth_getFilterLogs - IoTeX RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on IoTeX. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **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_getFilterLogs` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on IoTeX
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xA00744882684C3e4747fAEFd68D283eA44099D03"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xA00744882684C3e4747fAEFd68D283eA44099D03'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "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)
    }

    contractAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/iotex/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/iotex/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/iotex/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/iotex/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - IoTeX RPC Method

# eth_getLogs - IoTeX RPC Method

Returns an array of all logs matching a given filter object on IoTeX.

> **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

The `eth_getLogs` method serves these key scenarios for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on IoTeX for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on IoTeX
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on IoTeX.

```javascript
const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if IoTeX enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on IoTeX, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## 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_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "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)
    }

    contractAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/iotex/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/iotex/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - IoTeX RPC Method

# 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

---

## eth_getTransactionByHash - IoTeX RPC Method

# eth_getTransactionByHash - IoTeX RPC Method

Returns the information about a transaction by transaction hash on IoTeX.

> **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_getTransactionByHash` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on IoTeX
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on IoTeX. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on IoTeX. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## 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_getTransactionByHash",
    "params": ["0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    txHash := common.HexToHash("0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/iotex/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - IoTeX RPC Method

# eth_getTransactionCount - IoTeX RPC Method

Returns the number of transactions sent from an address on IoTeX, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **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_getTransactionCount` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on IoTeX
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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_getTransactionCount",
    "params": [
      "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "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_getTransactionCount',
    params: ['0xA00744882684C3e4747fAEFd68D283eA44099D03', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('IoTeX nonce:', nonce);

// 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 nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xA00744882684C3e4747fAEFd68D283eA44099D03'
nonce = get_transaction_count(address)
print(f'IoTeX nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("IoTeX nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on IoTeX:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xA00744882684C3e4747fAEFd68D283eA44099D03');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/iotex/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/iotex/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/iotex/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - IoTeX RPC Method

# eth_getTransactionReceipt - IoTeX RPC Method

Returns the receipt of a transaction by transaction hash on IoTeX. Receipt is only available for mined transactions.

> **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_getTransactionReceipt` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on IoTeX and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on IoTeX. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on IoTeX, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## 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_getTransactionReceipt",
    "params": ["0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    txHash := common.HexToHash("0x839fcf7f5deeefd02960f393f67a9a2b8ee993683d397757c74edf1667ffb0f8")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/iotex/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/iotex/eth_getLogs) - Query logs by filter

---

## eth_hashrate - IoTeX RPC Method

# eth_hashrate - IoTeX RPC Method

Returns the legacy `eth_hashrate` compatibility value on IoTeX. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **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.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## 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_hashrate",
    "params": [],
    "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_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('IoTeX hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('IoTeX hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'IoTeX hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'IoTeX hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("IoTeX hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/iotex/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/iotex/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/iotex/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - IoTeX RPC Method

# eth_maxPriorityFeePerGas - IoTeX RPC Method

Returns the current suggested priority fee (tip) per gas in wei on IoTeX. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **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_maxPriorityFeePerGas` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on IoTeX
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## 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_maxPriorityFeePerGas",
    "params": [],
    "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_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('IoTeX priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'IoTeX priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "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)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("IoTeX priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on IoTeX:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on IoTeX:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/iotex/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/iotex/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - IoTeX RPC Method

# eth_mining - IoTeX RPC Method

Checks the legacy `eth_mining` compatibility method on IoTeX. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **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.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## 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_mining",
    "params": [],
    "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_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('IoTeX mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('IoTeX mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'IoTeX mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'IoTeX mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("IoTeX mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/iotex/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/iotex/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/iotex/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - IoTeX RPC Method

# eth_newBlockFilter - IoTeX RPC Method

Creates a filter on IoTeX that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **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_newBlockFilter` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Block Monitoring** - Detect new blocks on IoTeX as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "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)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on IoTeX:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/iotex/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/iotex/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/iotex/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/iotex/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - IoTeX RPC Method

# eth_newFilter - IoTeX RPC Method

Creates a filter object on IoTeX based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **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_newFilter` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Event Monitoring** - Subscribe to specific contract events on IoTeX such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xA00744882684C3e4747fAEFd68D283eA44099D03',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "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)
    }

    contractAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on IoTeX:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xA00744882684C3e4747fAEFd68D283eA44099D03',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/iotex/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/iotex/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/iotex/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/iotex/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/iotex/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - IoTeX RPC Method

# eth_newPendingTransactionFilter - IoTeX RPC Method

Creates a filter on IoTeX that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **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_newPendingTransactionFilter` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Mempool Monitoring** - Observe unconfirmed transactions on IoTeX to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on IoTeX...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on IoTeX:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/iotex/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/iotex/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/iotex/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - IoTeX RPC Method

# eth_protocolVersion - IoTeX RPC Method

Returns the current Ethereum protocol version used by the IoTeX node.

> **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_protocolVersion` is useful for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## 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_protocolVersion",
    "params": [],
    "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_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('IoTeX protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('IoTeX protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'IoTeX protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'IoTeX protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("IoTeX protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of IoTeX nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/iotex/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/iotex/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/iotex/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - IoTeX RPC Method

# eth_sendRawTransaction - IoTeX RPC Method

Submits a pre-signed transaction for broadcast to IoTeX.

> **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

The `eth_sendRawTransaction` method serves these key scenarios for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to IoTeX
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xA00744882684C3e4747fAEFd68D283eA44099D03', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the IoTeX mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## 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_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/iotex/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "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)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/iotex/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/iotex/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - IoTeX RPC Method

# eth_sendTransaction - IoTeX RPC Method

Creates and sends a new transaction from an unlocked account on IoTeX. The node signs the transaction server-side using the private key associated with the `from` address.

> **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.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DePIN builders, IoT device manufacturers, and real-world AI application developers in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('IoTeX tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('IoTeX tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'IoTeX tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'IoTeX tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "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)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("IoTeX tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on IoTeX dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/iotex/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/iotex/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - IoTeX RPC Method

# eth_signTransaction - IoTeX RPC Method

Signs a transaction with the private key of the specified account on IoTeX without submitting it to the network.

> **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.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DePIN builders, IoT device manufacturers, and real-world AI application developers in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed IoTeX tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed IoTeX tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "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)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed IoTeX tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on IoTeX:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/iotex/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/iotex/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/iotex/eth_accounts) - List accounts available for signing

---

## eth_syncing - IoTeX RPC Method

# eth_syncing - IoTeX RPC Method

Returns the sync status of your IoTeX node - either `false` when fully synced, or an object describing the sync progress.

> **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_syncing` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## 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_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('IoTeX node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('IoTeX node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "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)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("IoTeX node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/iotex/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/iotex/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/iotex/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/iotex/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - IoTeX RPC Method

# eth_uninstallFilter - IoTeX RPC Method

Removes a filter on IoTeX that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **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_uninstallFilter` is important for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## 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_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/iotex/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/iotex/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/iotex/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/iotex/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/iotex/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - IoTeX RPC Method

# net_listening - IoTeX RPC Method

Checks whether the connected IoTeX client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **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

`net_listening` is useful for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## 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": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('IoTeX node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// 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: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'IoTeX node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("IoTeX node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/iotex/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/iotex/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/iotex/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/iotex/web3_clientVersion) - Get node client info

---

## net_peerCount - IoTeX RPC Method

# net_peerCount - IoTeX RPC Method

Returns the number of peers currently connected to your IoTeX node.

> **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

`net_peerCount` is important for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific IoTeX deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## 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": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`IoTeX peers: ${peerCount}`);

// 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: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'IoTeX peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("IoTeX peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of IoTeX nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/iotex/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/iotex/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/iotex/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/iotex/web3_clientVersion) - Get node client info

---

## net_version - IoTeX RPC Method

# net_version - IoTeX RPC Method

Returns the current network ID on IoTeX as a decimal string. The network ID identifies which network the node is connected to.

> **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

`net_version` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Endpoint Identification** - Confirm your application is connected to the expected IoTeX network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## 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": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('IoTeX network ID:', networkId);

// 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: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'IoTeX network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("IoTeX network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/iotex/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/iotex/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/iotex/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/iotex/eth_syncing) - Check node sync progress

---

## web3_clientVersion - IoTeX RPC Method

# web3_clientVersion - IoTeX RPC Method

Returns the current client software version string for your IoTeX node, including the client name, version number, OS, and runtime.

> **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

`web3_clientVersion` is valuable for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## 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": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('IoTeX client:', clientVersion);

// 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: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'IoTeX client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("IoTeX client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/iotex/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/iotex/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/iotex/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/iotex/net_peerCount) - Get number of connected peers

---

## web3_sha3 - IoTeX RPC Method

# web3_sha3 - IoTeX RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on IoTeX.

> **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.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## 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": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/iotex/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/iotex/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/iotex/web3_clientVersion) - Get node client version

---

## Kusama RPC with Dwellir

# Kusama RPC with Dwellir

## Kusama RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Kusama supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Kusama?

Kusama is Polkadot’s canary network, offering the same Substrate architecture with faster governance and real economic conditions. It is the proving ground for runtime features before they ship to Polkadot, making it ideal for teams that need production-grade infrastructure with rapid iteration cycles.

### **Fast Iteration with Economic Finality**

- Governance cycles finalize upgrades in **7 days**, letting you ship runtime changes weeks before Polkadot equivalents.
- Real staking economics and on-chain treasury make Kusama suitable for live user pilots and incentivized testing.
- Shared validator set delivers secure finality (\~6s blocks) while preserving flexibility for experimental features.

### **Early Access to Substrate Innovations**

- New runtime pallets, XCM improvements, and networking upgrades land on Kusama first, giving you a head start on upcoming Polkadot capabilities.
- Developers can validate performance at scale without waiting for Polkadot release windows.
- Canary parachains (Statemine, Karura, Hydration, and more) provide a rich ecosystem for cross-chain experimentation.

### **Production Tooling & Ecosystem Depth**

- Fully compatible with the Polkadot JS stack, Subxt, py-substrate-interface, and Dwellir Sidecar REST APIs.
- Rich telemetry, explorers (Subscan, Statescan), and infrastructure partners support monitoring and analytics.
- Seamlessly migrate winning features to Polkadot once product-market fit is proven.

## Quick Start with Kusama

Connect to Kusama’s relay chain endpoints and Sidecar REST surface with Dwellir.

### Installation & Setup

curl (HTTP JSON-RPC)
JavaScript (polkadot.js)
Rust (subxt)
Python (py-substrate-interface)

```bash
curl -s https://api-kusama.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function main() {
  const provider = new WsProvider('wss://api-kusama.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });

  const [chain, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.version(),
  ]);

  console.log(`Connected to ${chain.toString()} v${version.toString()}`);

  // Subscribe to finalized blocks
  const unsub = await api.rpc.chain.subscribeFinalizedHeads((header) => {
    console.log(`Finalized block #${header.number} at ${header.hash}`);
  });

  // Stop subscription after 3 blocks
  setTimeout(async () => {
    await unsub();
    await api.disconnect();
  }, 18000);
}

main().catch(console.error);
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[subxt::subxt(runtime_metadata_path = "./metadata/kusama.scale" )]
pub mod kusama {}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-kusama.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let header = api.rpc().block_header(None).await?.expect("latest header");
    println!("Latest block: #{:?} (hash {:?})", header.number, header.hash());

    let account = api.storage().system().account(
        &"E8MByjWbS49hmzFM1U5rvFJES1Xgz1TSBAZLiYqZQiFTNUY".parse()?
    ).await?;
    println!("Free balance: {} KSM", account.data.free);

    Ok(())
}
```

```python
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(
    url="wss://api-kusama.n.dwellir.com/YOUR_API_KEY",
    type_registry_preset="kusama"
)

chain = substrate.rpc_request("system_chain", [])
print(f"Connected to {chain['result']}")

head = substrate.rpc_request("chain_getFinalizedHead", [])
print(f"Finalized head: {head['result']}")

account_info = substrate.query(
    module='System',
    storage_function='Account',
    params=['E8MByjWbS49hmzFM1U5rvFJES1Xgz1TSBAZLiYqZQiFTNUY']
)

print(f"Free: {account_info['data']['free']}")
```

## Network Information

| Parameter            | Value            | Details                  |
| -------------------- | ---------------- | ------------------------ |
| Genesis Hash         | 0xb0a8d493…3dafe | Relay chain              |
| Native Token         | KSM              | 12 decimals              |
| SS58 Prefix          | 2                | Address format           |
| Runtime Spec Version | 1007001          | As of 3 Oct 2025         |
| Transaction Version  | 26               | state\_getRuntimeVersion |
| Explorer             | Subscan          | kusama.subscan.io        |

Kusama operates as a relay chain without a parent relay. Parachain IDs are allocated per project; refer to individual parachain docs for cross-chain calls. Runtime and transaction versions above reflect the live values queried via `state_getRuntimeVersion` on 3 October 2025.

## API Reference

Kusama exposes the same Substrate RPC namespaces as Polkadot, covering node telemetry, block production, storage access, and finality tracking.

## Common Integration Patterns

### Track Finality with GRANDPA and BEEFY

```typescript
const finalizedHeads = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`GRANDPA finalized #${header.number}`);
});

const beefySub = await api.rpc.beefy.subscribeJustifications((event) => {
  console.log('BEEFY justification', event);
});
```

Combine GRANDPA finalized heads with `beefy_subscribeJustifications` to monitor parachain finality for bridges and XCMP relayers.

### Paginate Large Storage Scans

```typescript
const page = await api.rpc.state.getKeysPaged(
  '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
  100,
  '0x',
  null
);

console.log('Fetched', page.length, 'System.Account keys');
```

Use `state_getKeysPaged` with archive access to traverse large storage maps without overwhelming RPC quotas.

### Decode Fees Before Submission

```typescript
const ext = api.tx.balances.transferAllowDeath(dest, amount);
const info = await api.rpc.payment.queryInfo(ext.toHex());
console.log(`PartialFee: ${info.partialFee.toHuman()}`);
```

Estimate transaction costs using `payment_queryInfo` so you can bound fees before broadcasting to Kusama.

## Performance Best Practices

- Prefer WebSocket connections for subscriptions, finality, and multi-round queries.
- Cache runtime metadata (`api.runtimeVersion`, type bundles) and reuse the ApiPromise instance across requests.
- Shard heavy workloads across archive nodes if you need deep historical access; avoid full-chain scans without pagination.
- Back off exponentially on retries when encountering `isSyncing` or transient `-32010` errors.
- Use Sidecar REST for read-heavy explorers when SCALE decoding is unnecessary.

## Troubleshooting

- **WebSocket handshake fails** – Confirm your API key is appended exactly as provided and outbound TCP/443 is open.
- **Invalid SS58 address** – Ensure addresses use prefix `2`. Convert from Polkadot (prefix 0) with `@polkadot/util-crypto` helpers.
- **Type errors in clients** – Refresh metadata (`api.runtimeMetadata`) after runtime upgrades; Kusama upgrades more frequently than Polkadot.
- **Extrinsic rejected** – Decode the dispatch error via `api.registry.findMetaError` to surface module/error details.
- **rateLimit/TooManyRequests** – Implement per-IP backoff and share a single connection pool across services.

## Smoke Tests

Run these baseline checks against production endpoints (values captured 3 Oct 2025):

```bash
# Node health (peers: 68, isSyncing: false)
curl -s https://api-kusama.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}'

# Latest block header (#30363294)
curl -s https://api-kusama.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"chain_getHeader","params":[]}'

# Block hash for #30363295 (0x028651…2e0c)
curl -s https://api-kusama.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"chain_getBlockHash","params":["0x1cf4e9f"]}'

# Runtime version (specVersion 1007001, transactionVersion 26)
curl -s https://api-kusama.n.dwellir.com/YOUR_API_KEY \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"state_getRuntimeVersion","params":[]}'
```

Verify the response fields match the expected peers, block numbers, hashes, and version metadata before onboarding workloads.

## Migration Guide

- **Endpoints** – Replace Polkadot RPC URLs with `https://api-kusama.n.dwellir.com/YOUR_API_KEY` or `wss://api-kusama.n.dwellir.com/YOUR_API_KEY` across services.
- **Addresses** – Re-encode SS58 addresses with prefix `2`; Polkadot addresses (prefix 0) are not valid on Kusama.
- **Runtime Types** – Update your custom type bundles to match the Kusama spec (`specVersion 1007001` as of Oct 2025) and refresh metadata caches after each upgrade.
- **Fee Calibration** – Kusama uses different fee multipliers; re-run `payment_queryInfo` and adjust heuristics for tipping and priority fees.
- **Bridges & XCM** – Confirm target parachain IDs and HRMP channels; Kusama pairs differ from Polkadot equivalents.

## Resources & Tools

- [Kusama Network Portal](https://kusama.network/)
- [Kusama Subscan Explorer](https://kusama.subscan.io)
- [Polkadot Wiki – Kusama Section](https://wiki.polkadot.network/docs/kusama)
- [Parity Telemetry – Kusama](https://telemetry.polkadot.io/#list/Kusama)
- [Substrate Developer Hub](https://docs.substrate.io/)
- [Dwellir Dashboard – Get your API key](https://dashboard.dwellir.com/register)

---

## author_pendingExtrinsics - Kusama RPC Method

# author_pendingExtrinsics - Kusama RPC Method

Returns all pending extrinsics currently in the transaction pool on Kusama. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`author_pendingExtrinsics` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Kusama
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Kusama transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/kusama/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/kusama/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/kusama/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Kusama RPC Method

# author_rotateKeys - Kusama RPC Method

Generate a new set of session keys on Kusama. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`author_rotateKeys` is critical for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Validator Setup** - Generate initial session keys when setting up a new validator on parachain experimentation, early feature deployment, and production-grade testing with real value
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Kusama:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/kusama/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/kusama/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Kusama RPC Method

# author_submitAndWatchExtrinsic - Kusama RPC Method

Submits a signed extrinsic to Kusama and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Kusama
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for parachain experimentation, early feature deployment, and production-grade testing with real value
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://kusama-rpc.n.dwellir.com

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://kusama-rpc.n.dwellir.com');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://kusama-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://kusama-rpc.n.dwellir.com").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/kusama/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/kusama/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/kusama/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/kusama/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Kusama RPC Method

# author_submitExtrinsic - Kusama RPC Method

Submits a fully signed extrinsic to Kusama for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`author_submitExtrinsic` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Token Transfers** -- Send native tokens or assets between accounts on Kusama
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://kusama-rpc.n.dwellir.com").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/kusama/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/kusama/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Kusama RPC Method

# beefy_getFinalizedHead - Kusama RPC Method

Returns the block hash of the latest BEEFY-finalized block on Kusama. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`beefy_getFinalizedHead` is important for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on parachain experimentation, early feature deployment, and production-grade testing with real value
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://kusama-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://kusama-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/kusama/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/kusama/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Kusama RPC Method

# chain_getBlock - Kusama RPC Method

Retrieves complete block information from Kusama, including the block header, extrinsics, and justifications.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://kusama-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://kusama-rpc.n.dwellir.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://kusama-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/kusama/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/kusama/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/kusama/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Kusama RPC Method

# chain_getBlockHash - Kusama RPC Method

Returns the block hash for a given block number on Kusama. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`chain_getBlockHash` is fundamental for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Kusama
- **Block Navigation** - Navigate the blockchain history for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Kusama
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://kusama-rpc.n.dwellir.com'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Kusama for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Kusama state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Kusama network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/kusama/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/kusama/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Kusama RPC Method

# chain_getFinalizedHead - Kusama RPC Method

Returns the hash of the last finalized block on Kusama. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`chain_getFinalizedHead` is critical for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Kusama
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://kusama-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://kusama-rpc.n.dwellir.com', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Kusama:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/kusama/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/kusama/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Kusama RPC Method

# chain_getHeader - Kusama RPC Method

Returns the block header for a given hash on Kusama. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`chain_getHeader` is ideal for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Kusama
- **Chain Synchronization** - Track block production and monitor chain progress for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://kusama-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Kusama:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Kusama chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Kusama block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/kusama/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Kusama RPC Method

# chain_subscribeFinalizedHeads - Kusama RPC Method

Subscribe to receive notifications when blocks are finalized on Kusama. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Exchange Deposits** - Only credit funds after finalization for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://kusama-rpc.n.dwellir.com`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://kusama-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://kusama-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Kusama:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/kusama/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/kusama/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Kusama RPC Method

# chain_subscribeNewHeads - Kusama RPC Method

Subscribe to receive notifications when new block headers are produced on Kusama. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`chain_subscribeNewHeads` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Block Monitoring** - Track new blocks in real time on Kusama for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://kusama-rpc.n.dwellir.com`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://kusama-rpc.n.dwellir.com -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://kusama-rpc.n.dwellir.com'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Kusama as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Kusama:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/kusama/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/kusama/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Kusama RPC Method

# grandpa_roundState - Kusama RPC Method

Returns the state of the current GRANDPA finality round on Kusama when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`grandpa_roundState` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Kusama, critical for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/kusama/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/kusama/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/kusama/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Kusama RPC Method

# payment_queryFeeDetails - Kusama RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Kusama. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`payment_queryFeeDetails` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Kusama
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for parachain experimentation, early feature deployment, and production-grade testing with real value, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/kusama/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/kusama/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/kusama/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/kusama/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Kusama RPC Method

# payment_queryInfo - Kusama RPC Method

Estimates the fee for an encoded extrinsic on Kusama. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`payment_queryInfo` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Kusama
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/kusama/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/kusama/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/kusama/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/kusama/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Kusama RPC Method

# rpc_methods - Kusama RPC Method

Returns a list of all RPC methods exposed by the Kusama node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`rpc_methods` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Kusama node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Kusama endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://kusama-rpc.n.dwellir.com', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Kusama endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/kusama/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/kusama/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Kusama RPC Method

# state_call - Kusama RPC Method

Calls a runtime API function on Kusama and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`state_call` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/kusama/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/kusama/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/kusama/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/kusama/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/kusama/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - Kusama RPC Method

# state_getKeysPaged - Kusama RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Kusama. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`state_getKeysPaged` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Kusama
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://kusama-rpc.n.dwellir.com";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/kusama/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/kusama/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Kusama RPC Method

# state_getMetadata - Kusama RPC Method

Returns the runtime metadata for Kusama as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`state_getMetadata` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Kusama
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://kusama-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Kusama:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Kusama:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/kusama/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/kusama/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Kusama RPC Method

# state_getRuntimeVersion - Kusama RPC Method

Returns the runtime version information for Kusama, including the spec name, spec version, implementation version, and supported API versions.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`state_getRuntimeVersion` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Kusama
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://kusama-rpc.n.dwellir.com'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Kusama in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/kusama/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Kusama RPC Method

# state_getStorage - Kusama RPC Method

Returns the SCALE-encoded storage value for a given key on Kusama. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`state_getStorage` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Kusama
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/kusama/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/kusama/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Kusama RPC Method

# state_queryStorageAt - Kusama RPC Method

Queries multiple storage keys at a specific block on Kusama, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`state_queryStorageAt` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Kusama
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/kusama/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/kusama/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/kusama/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/kusama/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Kusama RPC Method

# system_chain - Kusama RPC Method

Returns the chain name of the Kusama network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`system_chain` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Network Verification** -- Confirm your application is connected to the correct Kusama network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Kusama"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://kusama-rpc.n.dwellir.com', 'Kusama');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/kusama/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/kusama/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/kusama/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/kusama/rpc_methods) -- List all available RPC methods

---

## system_health - Kusama RPC Method

# system_health - Kusama RPC Method

Returns the health status of the Kusama node, including peer count, sync state, and whether the node expects to have peers.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`system_health` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Kusama
- **Load Balancing** - Route requests only to healthy, fully synced nodes for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://kusama-rpc.n.dwellir.com'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://kusama-rpc.n.dwellir.com"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Kusama:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Kusama nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://kusama-rpc.n.dwellir.com')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/kusama/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Kusama RPC Method

# system_name - Kusama RPC Method

Returns the node implementation name on Kusama. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`system_name` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Kusama
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Kusama node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Kusama node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Kusama node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
name = substrate.rpc_request('system_name', [])['result']
print(f'Kusama node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Kusama node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Kusama nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/kusama/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/kusama/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/kusama/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/kusama/rpc_methods) -- List all available RPC methods

---

## system_properties - Kusama RPC Method

# system_properties - Kusama RPC Method

Returns the chain-specific properties for Kusama, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`system_properties` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Kusama
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/kusama/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/kusama/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/kusama/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/kusama/rpc_methods) -- List all available RPC methods

---

## system_version - Kusama RPC Method

# system_version - Kusama RPC Method

Returns the node implementation version string on Kusama. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Kusama?** Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

## When to Use This Method

`system_version` is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Kusama
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for parachain experimentation, early feature deployment, and production-grade testing with real value
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://kusama-rpc.n.dwellir.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://kusama-rpc.n.dwellir.com');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Kusama node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://kusama-rpc.n.dwellir.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Kusama node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://kusama-rpc.n.dwellir.com',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Kusama node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://kusama-rpc.n.dwellir.com')
version = substrate.rpc_request('system_version', [])['result']
print(f'Kusama node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://kusama-rpc.n.dwellir.com")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Kusama node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Kusama nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/kusama/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/kusama/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/kusama/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/kusama/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/kusama/rpc_methods) -- List all available RPC methods

---

## Linea - zkEVM Layer 2 Documentation

# Linea - zkEVM Layer 2 Documentation

## Linea RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Linea supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Linea?

Linea is ConsenSys's zkEVM Layer 2 solution, leveraging zero-knowledge proofs to deliver unmatched scalability and security. As a Type 2 zkEVM, Linea offers complete EVM equivalence with powerful scaling benefits:

### **Zero-Knowledge Performance**

- **12-second block times** - Fast finality with zkProof generation
- **Up to 100x lower costs** than Ethereum mainnet
- **3,000+ TPS capacity** - High throughput for demanding applications

### **Cryptographic Security**

- **Zero-knowledge proofs** - Mathematical guarantees of correctness
- **ConsenSys engineering** - Built by Ethereum infrastructure leaders
- **Full EVM equivalence** - Type 2 zkEVM with complete compatibility

### **Developer Excellence**

- **MetaMask integration** - Native support from day one
- **Infura compatibility** - Seamless ConsenSys ecosystem integration
- **Truffle & Hardhat ready** - Use your existing development tools

## Quick Start with Linea

Connect to Linea in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Linea mainnet
const provider = new JsonRpcProvider(
  'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Verify connection to Linea
const network = await provider.getNetwork();
console.log('Connected to Linea:', network.chainId === 59144n);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Linea mainnet
const web3 = new Web3(
  'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Linea:', chainId === 59144);

// Get current gas price
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http, defineChain } from 'viem';

// Define Linea chain
const linea = defineChain({
  id: 59144,
  name: 'Linea',
  network: 'linea',
  nativeCurrency: {
    decimals: 18,
    name: 'Ether',
    symbol: 'ETH',
  },
  rpcUrls: {
    default: {
      http: ['https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'],
    },
  },
  blockExplorers: {
    default: { name: 'LineaScan', url: 'https://lineascan.build' },
  },
});

// Create Linea client
const client = createPublicClient({
  chain: linea,
  transport: http(),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter   | Value      | Details        |
| ----------- | ---------- | -------------- |
| Chain ID    | 59144      | 0xe708 (hex)   |
| Block Time  | 12 seconds | Average        |
| Gas Token   | ETH        | Native token   |
| Rollup Type | zkEVM      | Zero-Knowledge |

## API Reference

Linea supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with zkEVM-specific optimizations. Access all standard methods plus L2-specific features.

## zkEVM-Specific Features

### Zero-Knowledge Proof Verification

Linea's zkEVM architecture provides unique capabilities:

```javascript
// Monitor L2 state root updates
async function getStateRoot(provider) {
  const block = await provider.getBlock('latest');

  // Access zkEVM-specific fields
  const stateRoot = block.stateRoot;
  const zkProofHash = block.zkProofHash; // Linea-specific

  return {
    blockNumber: block.number,
    stateRoot,
    zkProofHash,
    timestamp: block.timestamp
  };
}
```

### Gas Optimization for zkEVM

Optimize gas costs on Linea's zkEVM:

```javascript
// Estimate gas with zkEVM optimizations
async function estimateLineaGas(provider, tx) {
  // Get L2 execution gas
  const gasEstimate = await provider.estimateGas(tx);

  // zkEVM has different gas dynamics than optimistic rollups
  // No separate L1 data fee, but proof generation costs amortized
  const gasPrice = await provider.getGasPrice();

  // Add 10% buffer for zkEVM proof overhead
  const bufferedGas = gasEstimate * 110n / 100n;

  return {
    gasLimit: bufferedGas,
    gasPrice: gasPrice,
    estimatedCost: bufferedGas * gasPrice
  };
}
```

### Batch Transaction Processing

Leverage Linea's efficient batch processing:

```javascript
// Batch multiple transactions for optimal zkProof generation
async function batchTransactions(provider, transactions) {
  const wallet = new ethers.Wallet(privateKey, provider);
  const nonce = await wallet.getTransactionCount();

  const promises = transactions.map((tx, index) => {
    return wallet.sendTransaction({
      ...tx,
      nonce: nonce + index,
      // Linea handles batching efficiently in zkProof generation
      gasLimit: 100000n,
    });
  });

  const receipts = await Promise.all(promises);
  return receipts;
}
```

## Performance Optimizations

### 1. **Connection Pooling**

Maintain persistent connections for optimal performance:

```javascript
class LineaProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        {
          chainId: 59144,
          name: 'linea'
        }
      );
    }
    return this.instance;
  }
}
```

### 2. **Smart Contract Deployment**

Deploy contracts optimized for zkEVM:

```javascript
async function deployContract(provider, bytecode, abi) {
  const wallet = new ethers.Wallet(privateKey, provider);

  // zkEVM-optimized deployment
  const factory = new ethers.ContractFactory(abi, bytecode, wallet);

  // Linea-specific gas settings
  const contract = await factory.deploy({
    gasLimit: 3000000n, // Higher limit for complex contracts
    gasPrice: await provider.getGasPrice()
  });

  // Wait for zkProof generation and confirmation
  await contract.waitForDeployment();

  return contract.address;
}
```

### 3. **Event Monitoring**

Efficiently monitor events on Linea:

```javascript
// Optimized event filtering for zkEVM
async function watchEvents(contract, eventName) {
  const filter = contract.filters[eventName]();

  // Linea processes events in zkProof batches
  // Use larger block ranges for efficiency
  const BATCH_SIZE = 5000;

  contract.on(filter, (event) => {
    console.log('Event detected:', event);
    // Process event data
  });

  // For historical events
  const events = await contract.queryFilter(
    filter,
    -BATCH_SIZE, // Last 5000 blocks
    'latest'
  );

  return events;
}
```

## Common Integration Patterns

### Cross-Layer Messaging

Interact between Ethereum L1 and Linea L2:

```javascript
// Bridge assets from Ethereum to Linea
async function bridgeToLinea(l1Provider, l2Provider, amount) {
  // L1 bridge contract address
  const L1_BRIDGE = '0x...'; // Official Linea bridge

  const l1Wallet = new ethers.Wallet(privateKey, l1Provider);
  const bridgeContract = new ethers.Contract(
    L1_BRIDGE,
    bridgeABI,
    l1Wallet
  );

  // Initiate bridge transaction on L1
  const tx = await bridgeContract.bridgeETH({
    value: amount,
    gasLimit: 200000n
  });

  // Wait for L1 confirmation
  await tx.wait();

  // Monitor L2 for bridge completion (typically 10-20 minutes)
  // zkEVM finality is faster than optimistic rollups
  return tx.hash;
}
```

### DeFi Integration

Build DeFi applications on Linea:

```javascript
// Interact with DeFi protocols on Linea
async function swapTokens(provider, tokenA, tokenB, amount) {
  const wallet = new ethers.Wallet(privateKey, provider);

  // Connect to DEX on Linea
  const router = new ethers.Contract(
    ROUTER_ADDRESS,
    routerABI,
    wallet
  );

  // Approve token spending
  const tokenContract = new ethers.Contract(tokenA, erc20ABI, wallet);
  await tokenContract.approve(ROUTER_ADDRESS, amount);

  // Execute swap with Linea-optimized gas
  const tx = await router.swapExactTokensForTokens(
    amount,
    0, // Min amount out
    [tokenA, tokenB],
    wallet.address,
    Math.floor(Date.now() / 1000) + 3600, // 1 hour deadline
    {
      gasLimit: 250000n,
      gasPrice: await provider.getGasPrice()
    }
  );

  return tx;
}
```

## Troubleshooting

### Error: "Invalid chain ID"

Ensure you're using the correct chain ID for Linea:

```javascript
// Correct chain ID for Linea mainnet
const LINEA_CHAIN_ID = 59144; // or 0xe708 in hex

// Verify connection
const chainId = await provider.getNetwork().then(n => n.chainId);
if (chainId !== 59144n) {
  throw new Error(`Wrong network: expected Linea (59144), got ${chainId}`);
}
```

### Error: "Transaction underpriced"

Linea uses dynamic gas pricing. Always fetch current prices:

```javascript
// Get optimal gas price for Linea
async function getOptimalGasPrice(provider) {
  const gasPrice = await provider.getGasPrice();

  // Add 10% buffer for zkEVM processing
  const bufferedPrice = gasPrice * 110n / 100n;

  return bufferedPrice;
}
```

### Error: "Execution reverted"

Debug failed transactions with trace data:

```javascript
// Debug transaction on Linea
async function debugTransaction(provider, txHash) {
  try {
    // Get transaction receipt
    const receipt = await provider.getTransactionReceipt(txHash);

    if (receipt.status === 0) {
      // Use debug_traceTransaction for detailed error
      const trace = await provider.send('debug_traceTransaction', [
        txHash,
        { tracer: 'callTracer' }
      ]);

      console.log('Revert reason:', trace);
    }

    return receipt;
  } catch (error) {
    console.error('Debug failed:', error);
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Linea zkEVM:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-mainnet.example.com');

// After (Linea)
const provider = new JsonRpcProvider(
  'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

// Full EVM equivalence - contracts work identically
// Same development tools and libraries
// MetaMask and wallet support
// Note: Different chain ID (59144)
// Note: zkEVM gas dynamics differ from L1
// Note: Finality achieved through zkProofs
```

### From Other L2s

Migrating from optimistic rollups to Linea zkEVM:

```javascript
// Key differences from Optimistic L2s:
// 1. No challenge period - zkProofs provide instant finality
// 2. Different gas model - no separate L1 data fee
// 3. Faster withdrawals - hours instead of days

// Optimistic L2 (e.g., Optimism, Arbitrum)
const withdrawalPeriod = 7 * 24 * 60 * 60; // 7 days

// Linea zkEVM
const withdrawalPeriod = 8 * 60 * 60; // ~8 hours for zkProof generation
```

## Developer Resources

### Essential Tools

- [Linea Documentation](https://docs.linea.build)
- [LineaScan Explorer](https://lineascan.build)
- [Linea Bridge](https://bridge.linea.build)
- [Linea SDK](https://www.npmjs.com/package/@consensys/linea-sdk)

### Development Frameworks

- [Hardhat Configuration](https://docs.linea.build/developers/quickstart/deploy-smart-contract/hardhat)
- [Build on Linea Quickstart](https://docs.linea.build/developers/quickstart)

### Need Help?

- **Email**: <support@dwellir.com>
- **Discord**: Join our developer community
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Build the future of Web3 on Linea zkEVM with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Linea RPC Method

# debug_traceBlock - Linea RPC Method

Traces all transactions in a block on Linea by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Linea - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Linea
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Linea:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Linea blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/linea/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/linea/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/linea/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/linea/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Linea RPC Method

# debug_traceBlockByHash - Linea RPC Method

Traces all transactions in a block on Linea identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Linea - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Linea
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Linea:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Linea:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/linea/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/linea/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/linea/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/linea/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/linea/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Linea RPC Method

# debug_traceBlockByNumber - Linea RPC Method

Traces all transactions in a block on Linea identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Linea - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Linea execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Linea:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Linea:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/linea/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/linea/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/linea/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/linea/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Linea RPC Method

# debug_traceCall - Linea RPC Method

Traces a call on Linea without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Linea - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Linea
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "data": "0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
        "data": "0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
        "data": "0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    data: '0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    data: '0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    'data': '0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
        "data": "0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Linea to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Linea:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Linea:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/linea/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/linea/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/linea/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/linea/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Linea RPC Method

# debug_traceTransaction - Linea RPC Method

Traces a transaction execution on Linea by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Linea
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/linea/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/linea/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Linea RPC Method

# eth_accounts - Linea RPC Method

Returns a list of addresses owned by the client on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/linea/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/linea/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Linea RPC Method

# eth_blockNumber - Linea RPC Method

Returns the number of the most recent block on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_blockNumber` is fundamental for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Syncing Applications** - Keep your dApp in sync with the latest Linea blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Linea block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Linea block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Linea block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Linea block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Linea block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Linea:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Linea:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Linea node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/linea/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/linea/eth_syncing) - Check if node is still syncing

---

## eth_call - Linea RPC Method

# eth_call - Linea RPC Method

Executes a new message call immediately without creating a transaction on Linea. Used for reading smart contract state.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

The `eth_call` method serves these key scenarios for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Linea
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';
const walletAddress = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Linea. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Linea
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Linea

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "data": "0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "data": "0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    data := common.FromHex("0x70a08231000000000000000000000000e5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Linea RPC Method

# eth_chainId - Linea RPC Method

Returns the chain ID used for transaction signing on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_chainId` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/linea/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/linea/eth_syncing) - Check sync status

---

## eth_coinbase - Linea RPC Method

# eth_coinbase - Linea RPC Method

Checks the legacy `eth_coinbase` compatibility method on Linea. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Linea coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Linea coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Linea coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Linea coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Linea coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Linea nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/linea/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/linea/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/linea/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Linea RPC Method

# eth_estimateGas - Linea RPC Method

Estimates the gas necessary to execute a transaction on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Linea
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Linea.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Linea may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "to": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 data posting fee

# eth_estimateL1Fee - Estimate L1 data posting fee

Estimate L1 data posting fee on the Linea zkEVM network. This method helps calculate the additional cost of posting transaction data to Ethereum L1 as part of Linea's zkEVM rollup architecture.

## Overview

Linea zkEVM is a Layer 2 rollup that periodically submits batched transaction data and proofs to Ethereum L1. While most transaction execution happens on L2 with low gas costs, there's an additional fee component for the L1 data availability costs.

## Request Parameters

- `transaction` (`Object, required`): Transaction object to estimate L1 fee for

## Request Example

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [
          {
            "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5",
            "to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "gas": "0x5208",
            "gasPrice": "0x3b9aca00",
            "value": "0x1bc16d674ec80000",
            "data": "0x"
          }
        ],
        "id": 1
      }'
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated L1 fee in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c6bf526340"
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateL1Fee",
    "params": [
      {
        "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5",
        "to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "gas": "0x5208",
        "gasPrice": "0x3b9aca00",
        "value": "0x1bc16d674ec80000",
        "data": "0x"
      }
    ],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_estimateL1Fee',
    params: [
      {
        from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
        to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
        gas: '0x5208',
        gasPrice: '0x3b9aca00',
        value: '0x1bc16d674ec80000',
        data: '0x'
      }
    ],
    id: 1
  })
});

const data = await response.json();
console.log('L1 Fee:', data.result);

// Advanced L1 fee estimation with transaction cost breakdown
class LineaFeeEstimator {
  constructor(rpcUrl) {
    this.rpcUrl = rpcUrl;
  }

  async estimateL1Fee(transaction) {
    const response = await fetch(this.rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'eth_estimateL1Fee',
        params: [transaction],
        id: 1
      })
    });

    const data = await response.json();
    
    if (data.error) {
      throw new Error(`RPC Error: ${data.error.message}`);
    }

    return parseInt(data.result, 16);
  }

  async getFullFeeBreakdown(transaction) {
    try {
      // Estimate L2 gas cost
      const l2GasResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_estimateGas',
          params: [transaction],
          id: 1
        })
      });

      const l2GasData = await l2GasResponse.json();
      const l2GasEstimate = parseInt(l2GasData.result, 16);

      // Get current gas price
      const gasPriceResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_gasPrice',
          params: [],
          id: 1
        })
      });

      const gasPriceData = await gasPriceResponse.json();
      const gasPrice = parseInt(gasPriceData.result, 16);

      // Estimate L1 fee
      const l1Fee = await this.estimateL1Fee(transaction);

      // Calculate L2 execution cost
      const l2ExecutionCost = l2GasEstimate * gasPrice;

      return {
        l1Fee: l1Fee,
        l2ExecutionCost: l2ExecutionCost,
        totalEstimatedCost: l1Fee + l2ExecutionCost,
        gasEstimate: l2GasEstimate,
        gasPrice: gasPrice,
        breakdown: {
          l1FeePercentage: ((l1Fee / (l1Fee + l2ExecutionCost)) * 100).toFixed(2),
          l2FeePercentage: ((l2ExecutionCost / (l1Fee + l2ExecutionCost)) * 100).toFixed(2)
        }
      };
    } catch (error) {
      throw new Error(`Failed to get fee breakdown: ${error.message}`);
    }
  }

  async compareFeesByDataSize(baseTransaction, dataSizes) {
    const results = [];

    for (const size of dataSizes) {
      // Generate test data of specified size
      const testData = '0x' + '00'.repeat(size);
      
      const testTransaction = {
        ...baseTransaction,
        data: testData
      };

      try {
        const breakdown = await this.getFullFeeBreakdown(testTransaction);
        
        results.push({
          dataSize: size,
          dataSizeKB: (size / 1024).toFixed(2),
          l1Fee: breakdown.l1Fee,
          l2ExecutionCost: breakdown.l2ExecutionCost,
          totalCost: breakdown.totalEstimatedCost,
          l1FeePerByte: breakdown.l1Fee / size,
          costIncrease: size === dataSizes[0] ? 0 : 
            ((breakdown.totalEstimatedCost - results[0].totalCost) / results[0].totalCost * 100).toFixed(2)
        });
      } catch (error) {
        results.push({
          dataSize: size,
          error: error.message
        });
      }
    }

    return results;
  }

  async optimizeTransactionCost(transaction) {
    const recommendations = [];
    
    // Get baseline cost
    const baseline = await this.getFullFeeBreakdown(transaction);
    
    // Check if transaction has unnecessary data
    if (transaction.data && transaction.data.length > 2) {
      // Estimate with minimal data
      const minimalTx = { ...transaction, data: '0x' };
      const minimal = await this.getFullFeeBreakdown(minimalTx);
      
      const dataCostSavings = baseline.l1Fee - minimal.l1Fee;
      
      if (dataCostSavings > 0) {
        recommendations.push({
          type: 'data_optimization',
          description: 'Consider reducing transaction data size',
          potentialSavings: dataCostSavings,
          savingsPercentage: ((dataCostSavings / baseline.totalEstimatedCost) * 100).toFixed(2)
        });
      }
    }

    // Check gas optimization
    if (baseline.gasEstimate > 100000) {
      recommendations.push({
        type: 'gas_optimization',
        description: 'High gas usage detected - consider optimizing contract calls',
        currentGas: baseline.gasEstimate,
        suggestion: 'Review contract logic for gas efficiency'
      });
    }

    // Check if L1 fees dominate
    if (parseFloat(baseline.breakdown.l1FeePercentage) > 70) {
      recommendations.push({
        type: 'l1_fee_dominance',
        description: 'L1 fees represent majority of transaction cost',
        l1Percentage: baseline.breakdown.l1FeePercentage,
        suggestion: 'Consider batching transactions or reducing data payload'
      });
    }

    return {
      baseline: baseline,
      recommendations: recommendations,
      optimizationPotential: recommendations.length > 0
    };
  }
}

// Usage examples
const feeEstimator = new LineaFeeEstimator('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Basic L1 fee estimation
const l1Fee = await feeEstimator.estimateL1Fee({
  from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
  to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  value: '0x1bc16d674ec80000',
  data: '0x'
});

console.log(`L1 Fee: ${l1Fee} wei`);

// Full fee breakdown
const breakdown = await feeEstimator.getFullFeeBreakdown({
  from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
  to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  value: '0x1bc16d674ec80000',
  data: '0xa9059cbb000000000000000000000000recipient000000000000000000000000'
});

console.log('Fee Breakdown:', breakdown);

// Compare fees by data size
const dataSizeComparison = await feeEstimator.compareFeesByDataSize(
  {
    from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
    to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
  },
  [0, 100, 500, 1000, 5000] // bytes
);

console.log('Data Size Impact:', dataSizeComparison);

// Optimization suggestions
const optimization = await feeEstimator.optimizeTransactionCost({
  from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
  to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  data: '0xa9059cbb' + '0'.repeat(1000) // Large data payload
});

console.log('Optimization Analysis:', optimization);
```

```python
import requests
import json
from typing import Dict, List, Any, Optional

class LineaFeeEstimator:
    """Estimate L1 fees and analyze transaction costs on Linea zkEVM"""
    
    def __init__(self, rpc_url: str):
        self.rpc_url = rpc_url
    
    def estimate_l1_fee(self, transaction: Dict[str, Any]) -> int:
        """Estimate L1 data posting fee for a transaction"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_estimateL1Fee",
            "params": [transaction],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return int(data['result'], 16)
    
    def _make_rpc_call(self, method: str, params: List = None) -> Any:
        """Helper method for RPC calls"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params or [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def get_full_fee_breakdown(self, transaction: Dict[str, Any]) -> Dict[str, Any]:
        """Get complete fee breakdown including L1 and L2 costs"""
        
        # Estimate L2 gas
        l2_gas_estimate = int(self._make_rpc_call('eth_estimateGas', [transaction]), 16)
        
        # Get current gas price
        gas_price = int(self._make_rpc_call('eth_gasPrice'), 16)
        
        # Estimate L1 fee
        l1_fee = self.estimate_l1_fee(transaction)
        
        # Calculate L2 execution cost
        l2_execution_cost = l2_gas_estimate * gas_price
        
        total_cost = l1_fee + l2_execution_cost
        
        return {
            'l1_fee': l1_fee,
            'l2_execution_cost': l2_execution_cost,
            'total_estimated_cost': total_cost,
            'gas_estimate': l2_gas_estimate,
            'gas_price': gas_price,
            'breakdown': {
                'l1_fee_percentage': round((l1_fee / total_cost) * 100, 2) if total_cost > 0 else 0,
                'l2_fee_percentage': round((l2_execution_cost / total_cost) * 100, 2) if total_cost > 0 else 0
            }
        }
    
    def analyze_data_cost_impact(
        self,
        base_transaction: Dict[str, Any],
        data_payloads: List[str]
    ) -> List[Dict[str, Any]]:
        """Analyze how different data payloads affect L1 fees"""
        
        results = []
        
        for i, data in enumerate(data_payloads):
            test_tx = {**base_transaction, 'data': data}
            
            try:
                breakdown = self.get_full_fee_breakdown(test_tx)
                data_size = (len(data) - 2) // 2 if data.startswith('0x') else len(data) // 2
                
                result = {
                    'data_payload': data[:20] + '...' if len(data) > 20 else data,
                    'data_size_bytes': data_size,
                    'l1_fee': breakdown['l1_fee'],
                    'l2_execution_cost': breakdown['l2_execution_cost'],
                    'total_cost': breakdown['total_estimated_cost'],
                    'l1_fee_per_byte': breakdown['l1_fee'] / data_size if data_size > 0 else 0
                }
                
                # Calculate cost increase relative to first payload
                if i > 0 and results:
                    base_cost = results[0]['total_cost']
                    result['cost_increase_pct'] = round(
                        ((result['total_cost'] - base_cost) / base_cost) * 100, 2
                    ) if base_cost > 0 else 0
                else:
                    result['cost_increase_pct'] = 0
                
                results.append(result)
                
            except Exception as e:
                results.append({
                    'data_payload': data[:20] + '...' if len(data) > 20 else data,
                    'error': str(e)
                })
        
        return results
    
    def suggest_optimizations(self, transaction: Dict[str, Any]) -> Dict[str, Any]:
        """Analyze transaction and suggest cost optimizations"""
        
        baseline = self.get_full_fee_breakdown(transaction)
        suggestions = []
        
        # Check data optimization potential
        if transaction.get('data') and len(transaction['data']) > 2:
            minimal_tx = {**transaction, 'data': '0x'}
            minimal_cost = self.get_full_fee_breakdown(minimal_tx)
            
            data_cost_impact = baseline['l1_fee'] - minimal_cost['l1_fee']
            
            if data_cost_impact > 0:
                suggestions.append({
                    'type': 'data_optimization',
                    'description': 'Transaction data contributes significantly to L1 costs',
                    'potential_savings_wei': data_cost_impact,
                    'potential_savings_pct': round(
                        (data_cost_impact / baseline['total_estimated_cost']) * 100, 2
                    ),
                    'recommendation': 'Consider compressing data or using events for large payloads'
                })
        
        # Check gas efficiency
        if baseline['gas_estimate'] > 200000:
            suggestions.append({
                'type': 'gas_optimization',
                'description': f'High gas usage detected: {baseline["gas_estimate"]:,} gas',
                'recommendation': 'Review contract logic for gas efficiency improvements'
            })
        
        # Check fee composition
        if baseline['breakdown']['l1_fee_percentage'] > 80:
            suggestions.append({
                'type': 'l1_fee_dominance',
                'description': f'L1 fees dominate total cost ({baseline["breakdown"]["l1_fee_percentage"]}%)',
                'recommendation': 'Consider batching multiple operations into single transaction'
            })
        
        return {
            'baseline_cost': baseline,
            'optimization_suggestions': suggestions,
            'total_potential_savings': sum(
                s.get('potential_savings_wei', 0) for s in suggestions
            )
        }
    
    def compare_transaction_efficiency(
        self,
        transactions: List[Dict[str, Any]],
        labels: List[str] = None
    ) -> Dict[str, Any]:
        """Compare efficiency of different transaction approaches"""
        
        if labels is None:
            labels = [f"Transaction {i+1}" for i in range(len(transactions))]
        
        comparisons = []
        
        for i, (tx, label) in enumerate(zip(transactions, labels)):
            try:
                breakdown = self.get_full_fee_breakdown(tx)
                
                comparisons.append({
                    'label': label,
                    'total_cost': breakdown['total_estimated_cost'],
                    'l1_fee': breakdown['l1_fee'],
                    'l2_cost': breakdown['l2_execution_cost'],
                    'gas_estimate': breakdown['gas_estimate'],
                    'efficiency_score': breakdown['gas_estimate'] / breakdown['total_estimated_cost']
                })
            except Exception as e:
                comparisons.append({
                    'label': label,
                    'error': str(e)
                })
        
        # Find most efficient
        valid_comparisons = [c for c in comparisons if 'error' not in c]
        
        if valid_comparisons:
            most_efficient = min(valid_comparisons, key=lambda x: x['total_cost'])
            least_efficient = max(valid_comparisons, key=lambda x: x['total_cost'])
            
            return {
                'comparisons': comparisons,
                'most_efficient': most_efficient,
                'least_efficient': least_efficient,
                'cost_difference': least_efficient['total_cost'] - most_efficient['total_cost'],
                'efficiency_improvement_pct': round(
                    ((least_efficient['total_cost'] - most_efficient['total_cost']) /
                     least_efficient['total_cost']) * 100, 2
                )
            }
        
        return {'comparisons': comparisons}

# Usage examples
fee_estimator = LineaFeeEstimator('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY')

# Basic L1 fee estimation
transaction = {
    'from': '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
    'to': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
    'value': '0x1bc16d674ec80000',
    'data': '0xa9059cbb000000000000000000000000recipient000000000000000000000000'
}

l1_fee = fee_estimator.estimate_l1_fee(transaction)
print(f"L1 Fee: {l1_fee:,} wei")

# Full breakdown
breakdown = fee_estimator.get_full_fee_breakdown(transaction)
print(f"Total Cost: {breakdown['total_estimated_cost']:,} wei")
print(f"L1 Fee: {breakdown['l1_fee']:,} wei ({breakdown['breakdown']['l1_fee_percentage']}%)")
print(f"L2 Cost: {breakdown['l2_execution_cost']:,} wei ({breakdown['breakdown']['l2_fee_percentage']}%)")

# Data impact analysis
data_payloads = [
    '0x',  # Empty
    '0xa9059cbb' + '00' * 32,  # Basic ERC20 transfer
    '0xa9059cbb' + '00' * 100,  # Larger payload
    '0xa9059cbb' + '00' * 500   # Very large payload
]

data_analysis = fee_estimator.analyze_data_cost_impact(
    {'from': '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5', 'to': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'},
    data_payloads
)

print("\nData Size Impact Analysis:")
for result in data_analysis:
    if 'error' not in result:
        print(f"  {result['data_size_bytes']} bytes: {result['total_cost']:,} wei "
              f"(+{result['cost_increase_pct']}%)")

# Optimization suggestions
optimization = fee_estimator.suggest_optimizations(transaction)
print(f"\nOptimization Suggestions:")
for suggestion in optimization['optimization_suggestions']:
    print(f"  - {suggestion['description']}")
    print(f"    {suggestion['recommendation']}")
```

## Understanding L1 Fees on Linea

### Fee Components

1. **L2 Execution Fee**: Standard gas cost for transaction execution on Linea
2. **L1 Data Fee**: Cost of posting transaction data to Ethereum L1 for data availability

### Data Size Impact

L1 fees scale with transaction data size:

- Simple transfers: Minimal L1 fee
- Contract interactions: Moderate L1 fee based on calldata
- Large data payloads: Significant L1 fee component

### Cost Optimization Strategies

1. **Minimize Data**: Reduce unnecessary data in transactions
2. **Batch Operations**: Combine multiple operations into single transaction
3. **Use Events**: Emit events instead of storing large data on-chain
4. **Optimize Encoding**: Use efficient data encoding methods

## Common Use Cases

### 1. Transaction Cost Planning

```javascript
// Plan transaction costs before execution
async function planTransactionCosts(transactions) {
  const feeEstimator = new LineaFeeEstimator(rpcUrl);
  const plans = [];
  
  for (const tx of transactions) {
    const breakdown = await feeEstimator.getFullFeeBreakdown(tx);
    plans.push({
      transaction: tx,
      estimatedCost: breakdown.totalEstimatedCost,
      l1FeeRatio: breakdown.breakdown.l1FeePercentage,
      recommendation: breakdown.breakdown.l1FeePercentage > 70 ? 
        'Consider batching or data optimization' : 'Cost efficient'
    });
  }
  
  return plans.sort((a, b) => a.estimatedCost - b.estimatedCost);
}
```

### 2. Data Optimization Analysis

```python
def optimize_contract_call_data(base_transaction, data_variations):
    """Find most cost-effective data encoding"""
    
    fee_estimator = LineaFeeEstimator(rpc_url)
    results = []
    
    for name, data in data_variations.items():
        tx = {**base_transaction, 'data': data}
        breakdown = fee_estimator.get_full_fee_breakdown(tx)
        
        results.append({
            'encoding': name,
            'data_size': len(data) // 2 - 1,  # Hex bytes
            'total_cost': breakdown['total_estimated_cost'],
            'l1_fee': breakdown['l1_fee'],
            'efficiency': breakdown['l1_fee'] / (len(data) // 2 - 1)
        })
    
    # Sort by total cost
    return sorted(results, key=lambda x: x['total_cost'])
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate L2 execution gas
- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Get current L2 gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/linea/eth_feeHistory) - Historical fee data

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Linea documentation](https://www.dwellir.com/docs/linea).*

---

## eth_feeHistory - Linea RPC Method

# eth_feeHistory - Linea RPC Method

Returns historical gas fee data on Linea, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Linea without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Linea.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Linea) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/linea/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Linea RPC Method

# eth_gasPrice - Linea RPC Method

Returns the current gas price on Linea in wei.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Linea
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Linea. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Linea, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Linea: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Linea supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/linea/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/linea/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Linea RPC Method

# eth_getBalance - Linea RPC Method

Returns the balance of a given address on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getBalance` is fundamental for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Linea
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Linea
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Linea. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Linea`);
  return balance;
}

displayBalance('0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Linea at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Linea')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Linea')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Linea.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/linea/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/linea/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Linea RPC Method

# eth_getBlockByHash - Linea RPC Method

Returns information about a block by hash on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getBlockByHash` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Linea
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Linea.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Linea.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Linea RPC Method

# eth_getBlockByNumber - Linea RPC Method

Returns information about a block by block number on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getBlockByNumber` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Linea
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Linea with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Linea. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/linea/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/linea/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Linea RPC Method

# eth_getBlockReceipts - Linea RPC Method

Returns all transaction receipts for a block on Linea. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getBlockReceipts` is useful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Linea, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Linea. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xa5de967d7d780c598c5568e1489bdf66613aa11f7acbd7de75725ee4382c027b",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/linea/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/linea/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Linea RPC Method

# eth_getCode - Linea RPC Method

Returns the bytecode at a given address on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getCode` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Linea
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Linea:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Linea:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/linea/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/linea/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Linea RPC Method

# eth_getFilterChanges - Linea RPC Method

Polls a filter on Linea for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getFilterChanges` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Linea
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Linea:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/linea/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/linea/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/linea/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/linea/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/linea/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Linea RPC Method

# eth_getFilterLogs - Linea RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Linea. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getFilterLogs` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Linea
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/linea/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/linea/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/linea/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/linea/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Linea RPC Method

# eth_getLogs - Linea RPC Method

Returns an array of all logs matching a given filter object on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Linea for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Linea
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Linea.

```javascript
const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Linea enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Linea, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/linea/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/linea/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Linea RPC Method

# eth_getStorageAt - Linea RPC Method

Returns the value from a storage position at a given address on Linea. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getStorageAt` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **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 enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **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": [
    "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "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-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', '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-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';

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-linea-mainnet-archive.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 = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
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-linea-mainnet-archive.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-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    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 Linea:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.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-linea-mainnet-archive.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 = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';
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 Linea:`);
  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/linea/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/linea/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/linea/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Linea RPC Method

# eth_getTransactionByHash - Linea RPC Method

Returns the information about a transaction by transaction hash on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getTransactionByHash` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Linea
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Linea. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Linea. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/linea/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Linea RPC Method

# eth_getTransactionCount - Linea RPC Method

Returns the number of transactions sent from an address on Linea, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getTransactionCount` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Linea
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Linea nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'
nonce = get_transaction_count(address)
print(f'Linea nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Linea nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Linea:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/linea/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/linea/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/linea/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Linea RPC Method

# eth_getTransactionReceipt - Linea RPC Method

Returns the receipt of a transaction by transaction hash on Linea. Receipt is only available for mined transactions.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_getTransactionReceipt` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Linea and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Linea. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Linea, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc9e9cb9405a8e526ee8eb21e2aae56fe6df29590f8e4d44148f15c8f6a263128")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/linea/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/linea/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Linea RPC Method

# eth_hashrate - Linea RPC Method

Returns the legacy `eth_hashrate` compatibility value on Linea. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Linea hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Linea hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Linea hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Linea hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Linea hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/linea/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/linea/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Linea RPC Method

# eth_maxPriorityFeePerGas - Linea RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Linea. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Linea
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Linea priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Linea priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Linea priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Linea:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Linea:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/linea/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Linea RPC Method

# eth_mining - Linea RPC Method

Checks the legacy `eth_mining` compatibility method on Linea. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Linea mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Linea mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Linea mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Linea mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Linea mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/linea/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/linea/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Linea RPC Method

# eth_newBlockFilter - Linea RPC Method

Creates a filter on Linea that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_newBlockFilter` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Block Monitoring** - Detect new blocks on Linea as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Linea:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/linea/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/linea/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/linea/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Linea RPC Method

# eth_newFilter - Linea RPC Method

Creates a filter object on Linea based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_newFilter` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Event Monitoring** - Subscribe to specific contract events on Linea such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Linea:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/linea/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/linea/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/linea/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/linea/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/linea/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Linea RPC Method

# eth_newPendingTransactionFilter - Linea RPC Method

Creates a filter on Linea that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Mempool Monitoring** - Observe unconfirmed transactions on Linea to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for enterprise DeFi (Aave, Renzo), institutional cross-border payments via SWIFT pilots, and zkEVM-native applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Linea...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Linea:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/linea/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/linea/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/linea/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Linea RPC Method

# eth_protocolVersion - Linea RPC Method

Returns the current Ethereum protocol version used by the Linea node.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_protocolVersion` is useful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Linea protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Linea protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Linea protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Linea protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Linea protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Linea nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/linea/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/linea/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/linea/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Linea RPC Method

# eth_sendRawTransaction - Linea RPC Method

Submits a pre-signed transaction for broadcast to Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Linea
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Linea mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/linea/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/linea/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Linea RPC Method

# eth_sendTransaction - Linea RPC Method

Creates and sends a new transaction from an unlocked account on Linea. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Linea tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Linea tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Linea tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Linea tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Linea tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Linea dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/linea/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Linea RPC Method

# eth_signTransaction - Linea RPC Method

Signs a transaction with the private key of the specified account on Linea without submitting it to the network.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Linea tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Linea tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Linea tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Linea:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/linea/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/linea/eth_accounts) - List accounts available for signing

---

## eth_syncing - Linea RPC Method

# eth_syncing - Linea RPC Method

Returns the sync status of your Linea node - either `false` when fully synced, or an object describing the sync progress.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_syncing` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Linea node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Linea node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Linea node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/linea/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/linea/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/linea/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Linea RPC Method

# eth_uninstallFilter - Linea RPC Method

Removes a filter on Linea that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`eth_uninstallFilter` is important for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/linea/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/linea/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/linea/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/linea/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/linea/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Linea RPC Method

# net_listening - Linea RPC Method

Checks whether the connected Linea client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`net_listening` is useful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Linea node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Linea node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Linea node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/linea/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/linea/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/linea/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/linea/web3_clientVersion) - Get node client info

---

## net_peerCount - Linea RPC Method

# net_peerCount - Linea RPC Method

Returns the number of peers currently connected to your Linea node.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`net_peerCount` is important for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Linea deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Linea peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Linea peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Linea peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Linea nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/linea/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/linea/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/linea/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/linea/web3_clientVersion) - Get node client info

---

## net_version - Linea RPC Method

# net_version - Linea RPC Method

Returns the current network ID on Linea as a decimal string. The network ID identifies which network the node is connected to.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`net_version` is essential for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Endpoint Identification** - Confirm your application is connected to the expected Linea network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Linea network ID:', networkId);

// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Linea network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Linea network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/linea/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/linea/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/linea/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/linea/eth_syncing) - Check node sync progress

---

## rollup_gasPrices - Get zkEVM gas price oracle...

# rollup_gasPrices - Get zkEVM gas price oracle...

Get zkEVM gas price oracle data on the Linea network. This method provides comprehensive gas pricing information for the zkEVM rollup, including both L2 execution costs and L1 data availability fees.

## Overview

Linea zkEVM uses a sophisticated gas pricing mechanism that accounts for:

- **L2 Execution Costs**: Gas costs for transaction execution on the zkEVM
- **L1 Data Availability**: Costs for posting transaction data to Ethereum L1
- **Proof Generation**: Costs associated with generating zero-knowledge proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Gas price oracle data object containing current pricing information for the zkEVM rollup.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "l1GasPrice": "0x12a05f200",
    "l2GasPrice": "0x3b9aca00",
    "overhead": "0xbc0",
    "scalar": "0x684000",
    "decimals": "0x6"
  }
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_gasPrices",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_gasPrices',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Gas Prices:', data.result);

// Advanced gas price monitoring for Linea zkEVM
class LineaGasPriceMonitor {
  constructor(rpcUrl) {
    this.rpcUrl = rpcUrl;
    this.priceHistory = [];
  }

  async getGasPrices() {
    const response = await fetch(this.rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'rollup_gasPrices',
        params: [],
        id: 1
      })
    });

    const data = await response.json();
    
    if (data.error) {
      throw new Error(`RPC Error: ${data.error.message}`);
    }

    return data.result;
  }

  async getCurrentPricing() {
    try {
      // Get rollup gas prices
      const rollupPrices = await this.getGasPrices();
      
      // Get standard gas price for comparison
      const standardGasResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_gasPrice',
          params: [],
          id: 1
        })
      });

      const standardGasData = await standardGasResponse.json();
      const standardGasPrice = parseInt(standardGasData.result, 16);

      return {
        timestamp: Date.now(),
        rollupPrices: rollupPrices,
        standardGasPrice: standardGasPrice,
        formattedPrices: this.formatPrices(rollupPrices, standardGasPrice)
      };
    } catch (error) {
      throw new Error(`Failed to get pricing: ${error.message}`);
    }
  }

  formatPrices(rollupPrices, standardGasPrice) {
    return {
      standardGasPrice: {
        wei: standardGasPrice,
        gwei: (standardGasPrice / 1e9).toFixed(2),
        eth: (standardGasPrice / 1e18).toFixed(8)
      },
      rollupData: rollupPrices // This will depend on actual response format
    };
  }

  async trackPriceHistory(duration = 3600000, interval = 60000) {
    // Track gas prices for specified duration (default 1 hour) at intervals (default 1 minute)
    const startTime = Date.now();
    const endTime = startTime + duration;

    console.log(`Starting price tracking for ${duration / 60000} minutes...`);

    while (Date.now() < endTime) {
      try {
        const pricing = await this.getCurrentPricing();
        this.priceHistory.push(pricing);
        
        console.log(`Price update: ${pricing.formattedPrices.standardGasPrice.gwei} gwei`);
        
        await new Promise(resolve => setTimeout(resolve, interval));
      } catch (error) {
        console.error('Price tracking error:', error.message);
        await new Promise(resolve => setTimeout(resolve, interval));
      }
    }

    return this.analyzePriceHistory();
  }

  analyzePriceHistory() {
    if (this.priceHistory.length === 0) {
      return { error: 'No price history available' };
    }

    const prices = this.priceHistory.map(p => p.standardGasPrice);
    const sortedPrices = [...prices].sort((a, b) => a - b);

    const analysis = {
      duration: {
        start: new Date(this.priceHistory[0].timestamp).toISOString(),
        end: new Date(this.priceHistory[this.priceHistory.length - 1].timestamp).toISOString(),
        dataPoints: this.priceHistory.length
      },
      statistics: {
        min: Math.min(...prices),
        max: Math.max(...prices),
        average: prices.reduce((sum, p) => sum + p, 0) / prices.length,
        median: sortedPrices[Math.floor(sortedPrices.length / 2)],
        volatility: this.calculateVolatility(prices)
      },
      trends: {
        direction: this.getTrend(prices),
        priceChange: prices[prices.length - 1] - prices[0],
        percentageChange: ((prices[prices.length - 1] - prices[0]) / prices[0] * 100).toFixed(2)
      },
      recommendations: this.generateRecommendations(prices)
    };

    return analysis;
  }

  calculateVolatility(prices) {
    if (prices.length < 2) return 0;
    
    const mean = prices.reduce((sum, p) => sum + p, 0) / prices.length;
    const variance = prices.reduce((sum, p) => sum + Math.pow(p - mean, 2), 0) / prices.length;
    return Math.sqrt(variance);
  }

  getTrend(prices) {
    if (prices.length < 2) return 'insufficient_data';
    
    const firstHalf = prices.slice(0, Math.floor(prices.length / 2));
    const secondHalf = prices.slice(Math.floor(prices.length / 2));
    
    const firstAvg = firstHalf.reduce((sum, p) => sum + p, 0) / firstHalf.length;
    const secondAvg = secondHalf.reduce((sum, p) => sum + p, 0) / secondHalf.length;
    
    const changePct = ((secondAvg - firstAvg) / firstAvg) * 100;
    
    if (changePct > 5) return 'increasing';
    if (changePct < -5) return 'decreasing';
    return 'stable';
  }

  generateRecommendations(prices) {
    const recommendations = [];
    const currentPrice = prices[prices.length - 1];
    const avgPrice = prices.reduce((sum, p) => sum + p, 0) / prices.length;
    const minPrice = Math.min(...prices);
    
    if (currentPrice > avgPrice * 1.2) {
      recommendations.push({
        type: 'high_gas_warning',
        message: 'Current gas price is significantly above average',
        suggestion: 'Consider waiting for lower gas prices or using lower priority'
      });
    }
    
    if (currentPrice <= minPrice * 1.1) {
      recommendations.push({
        type: 'optimal_timing',
        message: 'Current gas price is near historical low',
        suggestion: 'Good time to execute transactions'
      });
    }
    
    const volatility = this.calculateVolatility(prices);
    if (volatility > avgPrice * 0.1) {
      recommendations.push({
        type: 'high_volatility',
        message: 'Gas prices are highly volatile',
        suggestion: 'Monitor prices closely and be prepared to adjust'
      });
    }
    
    return recommendations;
  }

  async predictOptimalTiming(targetGasPrice) {
    const pricing = await this.getCurrentPricing();
    const currentPrice = pricing.standardGasPrice;
    
    if (currentPrice <= targetGasPrice) {
      return {
        optimal: true,
        currentPrice: currentPrice,
        targetPrice: targetGasPrice,
        recommendation: 'Execute transaction now'
      };
    }
    
    // Simple prediction based on recent trend
    const recentPrices = this.priceHistory.slice(-10).map(p => p.standardGasPrice);
    const trend = this.getTrend(recentPrices);
    
    let prediction = 'unknown';
    let estimatedWait = 'unknown';
    
    if (trend === 'decreasing') {
      prediction = 'prices_likely_to_drop';
      estimatedWait = 'monitor_for_15_30_minutes';
    } else if (trend === 'increasing') {
      prediction = 'prices_likely_to_rise';
      estimatedWait = 'consider_executing_soon';
    } else {
      prediction = 'prices_stable';
      estimatedWait = 'no_clear_trend';
    }
    
    return {
      optimal: false,
      currentPrice: currentPrice,
      targetPrice: targetGasPrice,
      prediction: prediction,
      estimatedWait: estimatedWait,
      recommendation: `Current: ${(currentPrice / 1e9).toFixed(2)} gwei, Target: ${(targetGasPrice / 1e9).toFixed(2)} gwei`
    };
  }

  async compareWithL1Costs() {
    try {
      // Get Linea gas prices
      const lineaPricing = await this.getCurrentPricing();
      
      // For comparison with Ethereum L1, you would need to call Ethereum mainnet
      // This is just an example structure
      const comparison = {
        linea: {
          gasPrice: lineaPricing.standardGasPrice,
          gasPriceGwei: lineaPricing.formattedPrices.standardGasPrice.gwei,
          estimatedTransferCost: lineaPricing.standardGasPrice * 21000 // ETH transfer
        },
        savings: {
          // This would be calculated with actual L1 data
          estimatedSavings: 'Requires L1 comparison data',
          savingsPercentage: 'Requires L1 comparison data'
        }
      };
      
      return comparison;
    } catch (error) {
      throw new Error(`Failed to compare costs: ${error.message}`);
    }
  }
}

// Usage examples
const gasPriceMonitor = new LineaGasPriceMonitor('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get current gas pricing
const currentPricing = await gasPriceMonitor.getCurrentPricing();
console.log('Current Gas Prices:', currentPricing.formattedPrices);

// Track prices for 10 minutes
const priceAnalysis = await gasPriceMonitor.trackPriceHistory(600000, 30000);
console.log('Price Analysis:', priceAnalysis);

// Check optimal timing for transaction
const optimalTiming = await gasPriceMonitor.predictOptimalTiming(20000000000); // 20 gwei target
console.log('Optimal Timing:', optimalTiming);

// Compare with L1 costs
const costComparison = await gasPriceMonitor.compareWithL1Costs();
console.log('Cost Comparison:', costComparison);
```

```python
import requests
import json
import time
import statistics
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta

class LineaGasPriceAnalyzer:
    """Analyze and monitor gas prices on Linea zkEVM"""
    
    def __init__(self, rpc_url: str):
        self.rpc_url = rpc_url
        self.price_history = []
    
    def get_rollup_gas_prices(self) -> Dict[str, Any]:
        """Get current rollup gas prices"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "rollup_gasPrices",
            "params": [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def get_standard_gas_price(self) -> int:
        """Get standard gas price for comparison"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_gasPrice",
            "params": [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return int(data['result'], 16)
    
    def get_comprehensive_pricing(self) -> Dict[str, Any]:
        """Get comprehensive gas pricing information"""
        
        rollup_prices = self.get_rollup_gas_prices()
        standard_gas_price = self.get_standard_gas_price()
        
        return {
            'timestamp': datetime.now().isoformat(),
            'rollup_data': rollup_prices,
            'standard_gas_price': standard_gas_price,
            'formatted': {
                'gas_price_wei': standard_gas_price,
                'gas_price_gwei': round(standard_gas_price / 1e9, 2),
                'gas_price_eth': round(standard_gas_price / 1e18, 8)
            },
            'transaction_costs': {
                'eth_transfer': standard_gas_price * 21000,  # Standard ETH transfer
                'erc20_transfer': standard_gas_price * 65000,  # Typical ERC20 transfer
                'swap': standard_gas_price * 150000  # Typical DEX swap
            }
        }
    
    def monitor_prices(
        self,
        duration_minutes: int = 60,
        interval_seconds: int = 60
    ) -> Dict[str, Any]:
        """Monitor gas prices over time"""
        
        start_time = datetime.now()
        end_time = start_time + timedelta(minutes=duration_minutes)
        
        print(f"Monitoring gas prices for {duration_minutes} minutes...")
        
        price_data = []
        
        while datetime.now() < end_time:
            try:
                pricing = self.get_comprehensive_pricing()
                price_data.append(pricing)
                self.price_history.append(pricing)
                
                print(f"Price update: {pricing['formatted']['gas_price_gwei']} gwei")
                
                time.sleep(interval_seconds)
                
            except Exception as e:
                print(f"Error monitoring prices: {e}")
                time.sleep(interval_seconds)
        
        return self._analyze_price_data(price_data)
    
    def _analyze_price_data(self, price_data: List[Dict]) -> Dict[str, Any]:
        """Analyze collected price data"""
        
        if not price_data:
            return {'error': 'No price data available'}
        
        gas_prices = [p['standard_gas_price'] for p in price_data]
        gwei_prices = [p['formatted']['gas_price_gwei'] for p in price_data]
        
        analysis = {
            'period': {
                'start': price_data[0]['timestamp'],
                'end': price_data[-1]['timestamp'],
                'data_points': len(price_data)
            },
            'statistics': {
                'min_wei': min(gas_prices),
                'max_wei': max(gas_prices),
                'average_wei': statistics.mean(gas_prices),
                'median_wei': statistics.median(gas_prices),
                'min_gwei': min(gwei_prices),
                'max_gwei': max(gwei_prices),
                'average_gwei': round(statistics.mean(gwei_prices), 2),
                'median_gwei': round(statistics.median(gwei_prices), 2),
                'std_dev_gwei': round(statistics.stdev(gwei_prices) if len(gwei_prices) > 1 else 0, 2)
            },
            'trends': self._calculate_trends(gas_prices),
            'volatility': self._calculate_volatility(gas_prices),
            'cost_analysis': self._analyze_transaction_costs(price_data)
        }
        
        return analysis
    
    def _calculate_trends(self, prices: List[int]) -> Dict[str, Any]:
        """Calculate price trends"""
        
        if len(prices) < 2:
            return {'trend': 'insufficient_data'}
        
        # Simple linear trend
        x = list(range(len(prices)))
        n = len(prices)
        
        # Calculate slope using least squares
        sum_x = sum(x)
        sum_y = sum(prices)
        sum_xy = sum(x[i] * prices[i] for i in range(n))
        sum_x2 = sum(x[i] ** 2 for i in range(n))
        
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        
        # Percentage change
        price_change = prices[-1] - prices[0]
        pct_change = (price_change / prices[0]) * 100
        
        trend_direction = 'increasing' if slope > 0 else 'decreasing' if slope < 0 else 'stable'
        
        return {
            'trend': trend_direction,
            'slope': slope,
            'price_change_wei': price_change,
            'percentage_change': round(pct_change, 2),
            'is_volatile': abs(pct_change) > 10
        }
    
    def _calculate_volatility(self, prices: List[int]) -> Dict[str, Any]:
        """Calculate price volatility metrics"""
        
        if len(prices) < 2:
            return {'volatility': 0}
        
        mean_price = statistics.mean(prices)
        variance = statistics.variance(prices)
        std_dev = statistics.stdev(prices)
        
        # Coefficient of variation (relative volatility)
        cv = (std_dev / mean_price) * 100 if mean_price > 0 else 0
        
        return {
            'standard_deviation': round(std_dev, 2),
            'variance': round(variance, 2),
            'coefficient_of_variation': round(cv, 2),
            'volatility_level': (
                'high' if cv > 15 else
                'medium' if cv > 5 else
                'low'
            )
        }
    
    def _analyze_transaction_costs(self, price_data: List[Dict]) -> Dict[str, Any]:
        """Analyze transaction costs over time"""
        
        cost_analysis = {
            'eth_transfer': [],
            'erc20_transfer': [],
            'swap': []
        }
        
        for data in price_data:
            costs = data['transaction_costs']
            cost_analysis['eth_transfer'].append(costs['eth_transfer'])
            cost_analysis['erc20_transfer'].append(costs['erc20_transfer'])
            cost_analysis['swap'].append(costs['swap'])
        
        result = {}
        for tx_type, costs in cost_analysis.items():
            result[tx_type] = {
                'min_cost_wei': min(costs),
                'max_cost_wei': max(costs),
                'avg_cost_wei': round(statistics.mean(costs)),
                'cost_range_wei': max(costs) - min(costs),
                'min_cost_usd': 'Requires ETH price data',
                'max_cost_usd': 'Requires ETH price data'
            }
        
        return result
    
    def recommend_optimal_timing(
        self,
        target_gas_price_gwei: float,
        transaction_type: str = 'eth_transfer'
    ) -> Dict[str, Any]:
        """Recommend optimal timing for transaction execution"""
        
        current_pricing = self.get_comprehensive_pricing()
        current_gwei = current_pricing['formatted']['gas_price_gwei']
        
        recommendation = {
            'current_price_gwei': current_gwei,
            'target_price_gwei': target_gas_price_gwei,
            'execute_now': current_gwei <= target_gas_price_gwei
        }
        
        if recommendation['execute_now']:
            recommendation['message'] = 'Current gas price meets target - execute now'
            recommendation['estimated_cost'] = current_pricing['transaction_costs'][transaction_type]
        else:
            price_diff = current_gwei - target_gas_price_gwei
            recommendation['message'] = f'Wait for lower prices (current: {current_gwei}, target: {target_gas_price_gwei})'
            recommendation['price_difference_gwei'] = round(price_diff, 2)
            
            # Simple prediction based on recent trend if available
            if len(self.price_history) > 5:
                recent_prices = [p['standard_gas_price'] for p in self.price_history[-5:]]
                trends = self._calculate_trends(recent_prices)
                
                if trends['trend'] == 'decreasing':
                    recommendation['prediction'] = 'Prices trending down - may reach target soon'
                elif trends['trend'] == 'increasing':
                    recommendation['prediction'] = 'Prices trending up - consider executing soon'
                else:
                    recommendation['prediction'] = 'Prices stable - monitor for changes'
        
        return recommendation
    
    def compare_with_ethereum_l1(self, eth_l1_gas_price_gwei: float) -> Dict[str, Any]:
        """Compare Linea costs with Ethereum L1"""
        
        linea_pricing = self.get_comprehensive_pricing()
        linea_gwei = linea_pricing['formatted']['gas_price_gwei']
        
        # Calculate savings for different transaction types
        savings_analysis = {}
        
        for tx_type, linea_gas_units in [
            ('eth_transfer', 21000),
            ('erc20_transfer', 65000),
            ('swap', 150000)
        ]:
            l1_cost_wei = int(eth_l1_gas_price_gwei * 1e9 * linea_gas_units)
            linea_cost_wei = linea_pricing['transaction_costs'][tx_type]
            
            savings_wei = l1_cost_wei - linea_cost_wei
            savings_pct = (savings_wei / l1_cost_wei) * 100 if l1_cost_wei > 0 else 0
            
            savings_analysis[tx_type] = {
                'l1_cost_wei': l1_cost_wei,
                'linea_cost_wei': linea_cost_wei,
                'savings_wei': savings_wei,
                'savings_percentage': round(savings_pct, 2),
                'cost_ratio': round(linea_cost_wei / l1_cost_wei, 3) if l1_cost_wei > 0 else 0
            }
        
        return {
            'comparison_timestamp': datetime.now().isoformat(),
            'l1_gas_price_gwei': eth_l1_gas_price_gwei,
            'linea_gas_price_gwei': linea_gwei,
            'price_ratio': round(linea_gwei / eth_l1_gas_price_gwei, 3) if eth_l1_gas_price_gwei > 0 else 0,
            'transaction_savings': savings_analysis
        }

# Usage examples
analyzer = LineaGasPriceAnalyzer('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY')

# Get current comprehensive pricing
pricing = analyzer.get_comprehensive_pricing()
print(f"Current gas price: {pricing['formatted']['gas_price_gwei']} gwei")
print(f"ETH transfer cost: {pricing['transaction_costs']['eth_transfer']:,} wei")

# Monitor prices for 30 minutes
price_analysis = analyzer.monitor_prices(duration_minutes=30, interval_seconds=120)
print("\nPrice Analysis:")
print(f"Average: {price_analysis['statistics']['average_gwei']} gwei")
print(f"Volatility: {price_analysis['volatility']['volatility_level']}")
print(f"Trend: {price_analysis['trends']['trend']}")

# Get timing recommendation
timing = analyzer.recommend_optimal_timing(target_gas_price_gwei=15.0)
print(f"\nTiming recommendation: {timing['message']}")

# Compare with Ethereum L1 (example with 50 gwei L1 price)
comparison = analyzer.compare_with_ethereum_l1(eth_l1_gas_price_gwei=50.0)
print(f"\nL1 vs Linea savings:")
for tx_type, data in comparison['transaction_savings'].items():
    print(f"  {tx_type}: {data['savings_percentage']}% savings")
```

## Understanding Gas Prices on Linea

### Price Components

1. **L2 Gas Price**: Cost per gas unit for execution on Linea zkEVM
2. **L1 Gas Price**: Current Ethereum L1 gas price for data posting
3. **Overhead**: Fixed overhead cost for L1 data posting
4. **Scalar**: Scaling factor for L1 cost calculation
5. **Decimals**: Decimal precision for calculations

### Cost Calculation

Total transaction cost = (L2 Gas × L2 Gas Price) + L1 Data Fee

Where L1 Data Fee considers:

- Transaction data size
- Current L1 gas price
- Overhead and scalar factors

## Common Use Cases

### 1. Gas Price Monitoring

```javascript
// Monitor gas prices for optimal transaction timing
async function monitorForOptimalGas(targetGwei, callback) {
  const monitor = new LineaGasPriceMonitor(rpcUrl);
  
  const checkPrice = async () => {
    const pricing = await monitor.getCurrentPricing();
    const currentGwei = pricing.formattedPrices.standardGasPrice.gwei;
    
    if (currentGwei <= targetGwei) {
      callback({
        optimal: true,
        currentPrice: currentGwei,
        targetPrice: targetGwei,
        message: 'Target price reached!'
      });
      return true;
    }
    
    return false;
  };
  
  // Check every 30 seconds
  const interval = setInterval(async () => {
    const optimal = await checkPrice();
    if (optimal) {
      clearInterval(interval);
    }
  }, 30000);
  
  // Initial check
  await checkPrice();
}
```

### 2. Cost Optimization

```python
def optimize_transaction_timing(analyzer, transactions, budget_gwei):
    """Find optimal timing for multiple transactions within budget"""
    
    optimization_plan = []
    
    for i, tx in enumerate(transactions):
        # Estimate transaction cost at different gas prices
        cost_estimates = []
        
        for gas_price_gwei in [10, 15, 20, 25, 30]:
            gas_price_wei = int(gas_price_gwei * 1e9)
            estimated_cost = tx['gas_estimate'] * gas_price_wei
            
            cost_estimates.append({
                'gas_price_gwei': gas_price_gwei,
                'estimated_cost_wei': estimated_cost,
                'within_budget': gas_price_gwei <= budget_gwei
            })
        
        # Find optimal price point
        optimal = next(
            (est for est in cost_estimates if est['within_budget']),
            cost_estimates[0]
        )
        
        optimization_plan.append({
            'transaction_id': i,
            'optimal_gas_price': optimal['gas_price_gwei'],
            'estimated_cost': optimal['estimated_cost_wei'],
            'cost_estimates': cost_estimates
        })
    
    return optimization_plan
```

### 3. Historical Analysis

```javascript
// Analyze historical gas price patterns
async function analyzeGasPricePatterns(monitor, days = 7) {
  const patterns = {
    hourlyAverages: {},
    dailyTrends: [],
    optimalTimes: []
  };
  
  // This would require storing historical data
  // For demonstration, showing structure
  
  // Simulate hourly analysis
  for (let hour = 0; hour < 24; hour++) {
    patterns.hourlyAverages[hour] = {
      averageGwei: 0, // Would be calculated from historical data
      transactionVolume: 0,
      volatility: 0
    };
  }
  
  // Identify optimal transaction times
  const sortedHours = Object.entries(patterns.hourlyAverages)
    .sort((a, b) => a[1].averageGwei - b[1].averageGwei);
  
  patterns.optimalTimes = sortedHours.slice(0, 6).map(([hour, data]) => ({
    hour: parseInt(hour),
    averageGwei: data.averageGwei,
    timeRange: `${hour}:00-${hour}:59 UTC`
  }));
  
  return patterns;
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Get current L2 gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/linea/eth_feeHistory) - Historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/linea/eth_estimateGas) - Estimate transaction gas
- [`rollup_getInfo`](https://www.dwellir.com/docs/linea/rollup_getInfo) - Get rollup configuration

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Linea documentation](https://www.dwellir.com/docs/linea).*

---

## rollup_getInfo - Get zkEVM rollup configuration

# rollup_getInfo - Get zkEVM rollup configuration

Get zkEVM rollup configuration on the Linea network. This method provides essential information about the zkEVM rollup parameters, settings, and operational details.

## Overview

Linea zkEVM is a Layer 2 scaling solution that uses zero-knowledge proofs to provide high throughput while maintaining Ethereum's security. The rollup configuration includes important parameters for:

- **Batch Processing**: How transactions are batched and processed
- **Proof Generation**: Zero-knowledge proof parameters
- **Bridge Operations**: L1 ↔ L2 asset bridging configuration
- **Network Parameters**: Chain ID, block times, and operational settings

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_getInfo",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup configuration object containing comprehensive information about the zkEVM rollup setup.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "mode": "zkevm",
    "chainId": "0xe708",
    "publicInputHash": "0x...",
    "stateRoot": "0x...",
    "withdrawalRoot": "0x...",
    "batchCommitment": "0x...",
    "prover": "0x...",
    "version": "1.0.0"
  }
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_getInfo",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_getInfo',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Rollup Info:', data.result);

// Advanced Linea zkEVM rollup information analyzer
class LineaRollupAnalyzer {
  constructor(rpcUrl) {
    this.rpcUrl = rpcUrl;
  }

  async getRollupInfo() {
    const response = await fetch(this.rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'rollup_getInfo',
        params: [],
        id: 1
      })
    });

    const data = await response.json();
    
    if (data.error) {
      throw new Error(`RPC Error: ${data.error.message}`);
    }

    return data.result;
  }

  async getComprehensiveRollupStatus() {
    try {
      // Get rollup info
      const rollupInfo = await this.getRollupInfo();
      
      // Get current chain info
      const chainIdResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_chainId',
          params: [],
          id: 1
        })
      });

      const chainData = await chainIdResponse.json();
      const chainId = parseInt(chainData.result, 16);

      // Get latest block info
      const blockResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_getBlockByNumber',
          params: ['latest', false],
          id: 1
        })
      });

      const blockData = await blockResponse.json();
      const latestBlock = blockData.result;

      return {
        timestamp: new Date().toISOString(),
        network: {
          name: 'Linea',
          chainId: chainId,
          type: 'zkEVM'
        },
        rollupConfig: rollupInfo,
        currentState: {
          latestBlock: parseInt(latestBlock.number, 16),
          blockHash: latestBlock.hash,
          timestamp: parseInt(latestBlock.timestamp, 16),
          gasLimit: parseInt(latestBlock.gasLimit, 16),
          gasUsed: parseInt(latestBlock.gasUsed, 16),
          utilization: ((parseInt(latestBlock.gasUsed, 16) / parseInt(latestBlock.gasLimit, 16)) * 100).toFixed(2)
        },
        analysis: this.analyzeRollupConfig(rollupInfo, chainId)
      };
    } catch (error) {
      throw new Error(`Failed to get comprehensive status: ${error.message}`);
    }
  }

  analyzeRollupConfig(rollupInfo, chainId) {
    const analysis = {
      networkType: 'zkEVM Rollup',
      securityModel: 'Zero-Knowledge Proofs',
      dataAvailability: 'Ethereum L1',
      features: [],
      optimizations: [],
      considerations: []
    };

    // Analyze chain ID
    if (chainId === 59144) {
      analysis.features.push('Linea Mainnet');
      analysis.features.push('Production Network');
    } else if (chainId === 59140) {
      analysis.features.push('Linea Testnet');
      analysis.features.push('Development Network');
    }

    // General zkEVM features
    analysis.features.push('EVM Compatibility');
    analysis.features.push('Zero-Knowledge Proofs');
    analysis.features.push('L1 Data Availability');
    analysis.features.push('Ethereum Security');

    // Optimizations
    analysis.optimizations.push('High Throughput');
    analysis.optimizations.push('Low Transaction Costs');
    analysis.optimizations.push('Fast Finality');
    analysis.optimizations.push('Ethereum Virtual Machine Compatibility');

    // Considerations
    analysis.considerations.push('Proof Generation Time');
    analysis.considerations.push('L1 Data Posting Costs');
    analysis.considerations.push('Bridge Withdrawal Delays');

    return analysis;
  }

  async compareWithOtherL2s() {
    const lineaInfo = await this.getComprehensiveRollupStatus();
    
    // This would be expanded with actual data from other L2s
    const comparison = {
      linea: {
        type: 'zkEVM',
        proofSystem: 'Zero-Knowledge',
        evmCompatibility: 'Full',
        dataAvailability: 'On-chain (Ethereum L1)',
        finality: 'Probabilistic → Proven',
        withdrawalTime: '~7 days (pending finalization)',
        advantages: [
          'Full EVM compatibility',
          'Strong security guarantees',
          'No trust assumptions beyond Ethereum',
          'Privacy-preserving proofs'
        ]
      },
      optimisticRollups: {
        type: 'Optimistic',
        proofSystem: 'Fraud Proofs',
        evmCompatibility: 'Full',
        dataAvailability: 'On-chain (Ethereum L1)',
        finality: 'Optimistic → Proven',
        withdrawalTime: '~7 days (challenge period)',
        tradeoffs: [
          'Faster transaction processing',
          'Lower computational overhead',
          'Challenge period required',
          'Potential for fraud challenges'
        ]
      },
      comparison: {
        security: 'zkEVM provides stronger guarantees',
        performance: 'Similar transaction throughput',
        costs: 'Comparable transaction fees',
        devExperience: 'Both offer full EVM compatibility'
      }
    };

    return comparison;
  }

  async monitorRollupHealth() {
    const health = {
      timestamp: new Date().toISOString(),
      status: 'unknown',
      metrics: {},
      alerts: []
    };

    try {
      const status = await this.getComprehensiveRollupStatus();
      
      // Check basic connectivity and latest block
      const blockAge = Date.now() / 1000 - status.currentState.timestamp;
      
      health.metrics = {
        latestBlock: status.currentState.latestBlock,
        blockAge: blockAge,
        gasUtilization: parseFloat(status.currentState.utilization),
        chainId: status.network.chainId
      };

      // Health checks
      if (blockAge > 300) { // 5 minutes
        health.alerts.push({
          severity: 'warning',
          message: `Latest block is ${Math.floor(blockAge / 60)} minutes old`,
          recommendation: 'Check network connectivity and block production'
        });
      }

      if (health.metrics.gasUtilization > 90) {
        health.alerts.push({
          severity: 'info',
          message: `High gas utilization: ${health.metrics.gasUtilization}%`,
          recommendation: 'Network is experiencing high usage'
        });
      }

      health.status = health.alerts.length === 0 ? 'healthy' : 
                    health.alerts.some(a => a.severity === 'error') ? 'unhealthy' : 'warning';

    } catch (error) {
      health.status = 'error';
      health.alerts.push({
        severity: 'error',
        message: `Failed to get rollup status: ${error.message}`,
        recommendation: 'Check RPC endpoint connectivity'
      });
    }

    return health;
  }

  async getNetworkCapacityInfo() {
    try {
      const status = await this.getComprehensiveRollupStatus();
      
      const capacity = {
        current: {
          blockGasLimit: status.currentState.gasLimit,
          blockGasUsed: status.currentState.gasUsed,
          utilizationPercentage: parseFloat(status.currentState.utilization)
        },
        theoretical: {
          maxTxPerSecond: 0, // Would be calculated based on average gas per tx
          maxTxPerBlock: 0,
          avgBlockTime: 0 // Would need historical data
        },
        estimates: {
          simpleTransfers: Math.floor(status.currentState.gasLimit / 21000),
          erc20Transfers: Math.floor(status.currentState.gasLimit / 65000),
          complexContracts: Math.floor(status.currentState.gasLimit / 200000)
        }
      };

      return capacity;
    } catch (error) {
      throw new Error(`Failed to get capacity info: ${error.message}`);
    }
  }

  async analyzeUpgradeability() {
    const rollupInfo = await this.getRollupInfo();
    
    // This would analyze the actual rollup configuration
    // For demonstration, providing general zkEVM upgrade analysis
    return {
      upgradeType: 'Governed Upgrades',
      governanceModel: 'Multi-signature or DAO governance',
      upgradeProcess: [
        'Proposal submission',
        'Community review',
        'Governance voting',
        'Implementation timeline',
        'Upgrade execution'
      ],
      considerations: [
        'Proof system upgrades may require redeployment',
        'Smart contract upgrades follow standard patterns',
        'L1 contract upgrades need careful coordination',
        'Backward compatibility maintenance'
      ],
      riskMitigation: [
        'Extensive testing on testnets',
        'Gradual rollout procedures',
        'Emergency pause mechanisms',
        'Rollback capabilities where possible'
      ]
    };
  }

  async getBridgeInfo() {
    // This would integrate with bridge contracts
    // For demonstration, providing general bridge information
    return {
      bridgeType: 'Canonical Bridge',
      supportedAssets: [
        'ETH (Native)',
        'ERC-20 Tokens',
        'ERC-721 NFTs',
        'ERC-1155 Multi-tokens'
      ],
      bridgeProcess: {
        deposit: {
          timeToL2: '~15 minutes',
          steps: [
            'Lock tokens on L1',
            'Wait for L1 confirmation',
            'Mint on L2',
            'Tokens available on L2'
          ]
        },
        withdrawal: {
          timeToL1: '~7 days',
          steps: [
            'Burn tokens on L2',
            'Include in batch',
            'Generate proof',
            'Submit to L1',
            'Finalization period',
            'Claim on L1'
          ]
        }
      },
      security: {
        model: 'Cryptographic proofs',
        assumptions: 'Ethereum L1 security',
        risks: [
          'Smart contract bugs',
          'Proof system vulnerabilities',
          'Bridge implementation issues'
        ]
      }
    };
  }
}

// Usage examples
const rollupAnalyzer = new LineaRollupAnalyzer('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get basic rollup info
const rollupInfo = await rollupAnalyzer.getRollupInfo();
console.log('Rollup Configuration:', rollupInfo);

// Get comprehensive status
const comprehensiveStatus = await rollupAnalyzer.getComprehensiveRollupStatus();
console.log('Network Status:', comprehensiveStatus);

// Monitor rollup health
const healthStatus = await rollupAnalyzer.monitorRollupHealth();
console.log('Health Status:', healthStatus.status);
console.log('Alerts:', healthStatus.alerts);

// Get network capacity info
const capacityInfo = await rollupAnalyzer.getNetworkCapacityInfo();
console.log('Network Capacity:', capacityInfo);

// Compare with other L2s
const comparison = await rollupAnalyzer.compareWithOtherL2s();
console.log('L2 Comparison:', comparison);

// Analyze upgradeability
const upgradeAnalysis = await rollupAnalyzer.analyzeUpgradeability();
console.log('Upgrade Model:', upgradeAnalysis);

// Get bridge information
const bridgeInfo = await rollupAnalyzer.getBridgeInfo();
console.log('Bridge Details:', bridgeInfo);
```

```python
import requests
import json
import time
from typing import Dict, List, Any, Optional
from datetime import datetime

class LineaRollupInfoAnalyzer:
    """Comprehensive analyzer for Linea zkEVM rollup information"""
    
    def __init__(self, rpc_url: str):
        self.rpc_url = rpc_url
    
    def get_rollup_info(self) -> Dict[str, Any]:
        """Get basic rollup configuration information"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "rollup_getInfo",
            "params": [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def _make_rpc_call(self, method: str, params: List = None) -> Any:
        """Helper method for making RPC calls"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params or [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def get_comprehensive_rollup_status(self) -> Dict[str, Any]:
        """Get comprehensive rollup status and configuration"""
        
        rollup_info = self.get_rollup_info()
        
        # Get additional network information
        chain_id = int(self._make_rpc_call('eth_chainId'), 16)
        latest_block = self._make_rpc_call('eth_getBlockByNumber', ['latest', False])
        
        block_number = int(latest_block['number'], 16)
        block_timestamp = int(latest_block['timestamp'], 16)
        gas_limit = int(latest_block['gasLimit'], 16)
        gas_used = int(latest_block['gasUsed'], 16)
        
        return {
            'timestamp': datetime.now().isoformat(),
            'network_info': {
                'name': 'Linea',
                'chain_id': chain_id,
                'type': 'zkEVM',
                'consensus': 'Zero-Knowledge Proofs'
            },
            'rollup_config': rollup_info,
            'current_state': {
                'latest_block': block_number,
                'block_hash': latest_block['hash'],
                'block_timestamp': block_timestamp,
                'gas_limit': gas_limit,
                'gas_used': gas_used,
                'gas_utilization': round((gas_used / gas_limit) * 100, 2),
                'block_age_seconds': int(time.time()) - block_timestamp
            },
            'analysis': self._analyze_rollup_configuration(rollup_info, chain_id)
        }
    
    def _analyze_rollup_configuration(
        self, 
        rollup_info: Dict[str, Any], 
        chain_id: int
    ) -> Dict[str, Any]:
        """Analyze rollup configuration and provide insights"""
        
        analysis = {
            'rollup_type': 'zkEVM (Zero-Knowledge Ethereum Virtual Machine)',
            'security_model': 'Cryptographic proofs with L1 data availability',
            'key_features': [
                'Full EVM compatibility',
                'Zero-knowledge proof validation',
                'Ethereum L1 data availability',
                'Trustless withdrawals',
                'Privacy-preserving computations'
            ],
            'network_classification': 'Mainnet' if chain_id == 59144 else 'Testnet',
            'performance_characteristics': {
                'finality': 'Probabilistic then cryptographically proven',
                'withdrawal_time': '~7 days (proof generation + challenge period)',
                'throughput': 'High (limited by gas limit)',
                'costs': 'Low L2 execution + L1 data costs'
            }
        }
        
        # Add specific insights based on chain
        if chain_id == 59144:  # Linea Mainnet
            analysis['environment'] = 'Production'
            analysis['considerations'] = [
                'Real value at risk',
                'Production-grade security',
                'Full audit coverage',
                'Mainnet gas costs apply'
            ]
        elif chain_id == 59140:  # Linea Testnet
            analysis['environment'] = 'Testing'
            analysis['considerations'] = [
                'Testing and development use',
                'No real value',
                'Latest features may be experimental',
                'Network resets possible'
            ]
        
        return analysis
    
    def monitor_rollup_performance(self, duration_minutes: int = 10) -> Dict[str, Any]:
        """Monitor rollup performance over time"""
        
        monitoring_data = []
        start_time = datetime.now()
        
        print(f"Monitoring rollup for {duration_minutes} minutes...")
        
        try:
            while (datetime.now() - start_time).seconds < duration_minutes * 60:
                status = self.get_comprehensive_rollup_status()
                monitoring_data.append(status)
                
                print(f"Block: {status['current_state']['latest_block']}, "
                      f"Utilization: {status['current_state']['gas_utilization']}%")
                
                time.sleep(30)  # Check every 30 seconds
                
        except KeyboardInterrupt:
            print("Monitoring stopped by user")
        
        return self._analyze_performance_data(monitoring_data)
    
    def _analyze_performance_data(self, monitoring_data: List[Dict]) -> Dict[str, Any]:
        """Analyze collected performance data"""
        
        if not monitoring_data:
            return {'error': 'No monitoring data collected'}
        
        block_numbers = [d['current_state']['latest_block'] for d in monitoring_data]
        gas_utilizations = [d['current_state']['gas_utilization'] for d in monitoring_data]
        block_ages = [d['current_state']['block_age_seconds'] for d in monitoring_data]
        
        # Calculate block production rate
        if len(block_numbers) > 1:
            blocks_produced = block_numbers[-1] - block_numbers[0]
            time_elapsed = (
                datetime.fromisoformat(monitoring_data[-1]['timestamp']) -
                datetime.fromisoformat(monitoring_data[0]['timestamp'])
            ).seconds
            avg_block_time = time_elapsed / blocks_produced if blocks_produced > 0 else 0
        else:
            avg_block_time = 0
            blocks_produced = 0
        
        return {
            'monitoring_period': {
                'start': monitoring_data[0]['timestamp'],
                'end': monitoring_data[-1]['timestamp'],
                'data_points': len(monitoring_data)
            },
            'block_production': {
                'blocks_produced': blocks_produced,
                'average_block_time': round(avg_block_time, 2),
                'block_range': f"{block_numbers[0]} - {block_numbers[-1]}"
            },
            'gas_utilization': {
                'average': round(sum(gas_utilizations) / len(gas_utilizations), 2),
                'min': min(gas_utilizations),
                'max': max(gas_utilizations),
                'trend': self._calculate_trend(gas_utilizations)
            },
            'network_health': {
                'consistent_block_production': blocks_produced > 0,
                'average_block_age': round(sum(block_ages) / len(block_ages), 2),
                'health_score': self._calculate_health_score(monitoring_data)
            }
        }
    
    def _calculate_trend(self, values: List[float]) -> str:
        """Calculate trend direction for a series of values"""
        
        if len(values) < 2:
            return 'insufficient_data'
        
        first_half = values[:len(values)//2]
        second_half = values[len(values)//2:]
        
        first_avg = sum(first_half) / len(first_half)
        second_avg = sum(second_half) / len(second_half)
        
        change_pct = ((second_avg - first_avg) / first_avg) * 100 if first_avg > 0 else 0
        
        if change_pct > 5:
            return 'increasing'
        elif change_pct < -5:
            return 'decreasing'
        else:
            return 'stable'
    
    def _calculate_health_score(self, monitoring_data: List[Dict]) -> float:
        """Calculate a health score for the rollup"""
        
        score = 100.0
        
        # Check for stale blocks
        avg_block_age = sum(d['current_state']['block_age_seconds'] for d in monitoring_data) / len(monitoring_data)
        if avg_block_age > 300:  # 5 minutes
            score -= 20
        elif avg_block_age > 120:  # 2 minutes
            score -= 10
        
        # Check gas utilization patterns
        gas_utils = [d['current_state']['gas_utilization'] for d in monitoring_data]
        avg_util = sum(gas_utils) / len(gas_utils)
        
        if avg_util > 95:  # Very high utilization
            score -= 15
        elif avg_util < 5:  # Very low utilization (might indicate issues)
            score -= 10
        
        return max(0, score)
    
    def compare_with_ethereum_l1(self, eth_l1_rpc_url: str = None) -> Dict[str, Any]:
        """Compare Linea with Ethereum L1 characteristics"""
        
        linea_status = self.get_comprehensive_rollup_status()
        
        comparison = {
            'linea_zkevm': {
                'type': 'Layer 2 zkEVM',
                'consensus': 'Zero-Knowledge Proofs',
                'finality': 'Probabilistic → Proven',
                'block_time': '~12 seconds',
                'gas_limit': linea_status['current_state']['gas_limit'],
                'transaction_throughput': 'High',
                'transaction_costs': 'Low'
            },
            'ethereum_l1': {
                'type': 'Layer 1 Blockchain',
                'consensus': 'Proof of Stake',
                'finality': 'Probabilistic',
                'block_time': '~12 seconds',
                'gas_limit': '~30M gas',
                'transaction_throughput': 'Limited',
                'transaction_costs': 'High'
            },
            'advantages_linea': [
                'Lower transaction costs',
                'Higher throughput capacity',
                'EVM compatibility',
                'Inherits Ethereum security',
                'Privacy features via zk-proofs'
            ],
            'advantages_l1': [
                'No additional trust assumptions',
                'Direct composability',
                'Immediate finality',
                'No bridge requirements',
                'Maximum decentralization'
            ]
        }
        
        return comparison
    
    def analyze_upgradeability_governance(self) -> Dict[str, Any]:
        """Analyze upgradeability and governance mechanisms"""
        
        return {
            'upgrade_mechanism': 'Governed Smart Contracts',
            'governance_model': {
                'type': 'Multi-signature or DAO governance',
                'participants': [
                    'Core development team',
                    'Community stakeholders',
                    'Security auditors',
                    'Ecosystem partners'
                ]
            },
            'upgrade_process': {
                'steps': [
                    '1. Proposal creation and review',
                    '2. Community discussion period',
                    '3. Technical evaluation',
                    '4. Governance voting',
                    '5. Implementation timeline',
                    '6. Staged rollout',
                    '7. Post-upgrade monitoring'
                ],
                'timeframes': {
                    'discussion_period': '1-2 weeks',
                    'voting_period': '1 week',
                    'implementation_delay': '1-2 weeks',
                    'total_process': '4-6 weeks minimum'
                }
            },
            'risk_mitigation': [
                'Extensive testnet validation',
                'Audit requirements',
                'Emergency pause mechanisms',
                'Gradual feature activation',
                'Rollback procedures where possible'
            ],
            'recent_upgrades': 'Check governance forum for latest information'
        }
    
    def get_bridge_integration_info(self) -> Dict[str, Any]:
        """Get information about bridge integrations and interoperability"""
        
        return {
            'canonical_bridge': {
                'purpose': 'Official L1 ↔ L2 asset transfer',
                'supported_assets': [
                    'ETH (native Ether)',
                    'ERC-20 tokens',
                    'ERC-721 NFTs',
                    'ERC-1155 multi-tokens'
                ],
                'security_model': 'zkEVM proof validation'
            },
            'bridge_process': {
                'deposits_l1_to_l2': {
                    'time': '~15 minutes',
                    'process': [
                        'Lock assets on L1',
                        'Wait for L1 confirmation',
                        'Automatic minting on L2',
                        'Assets available on L2'
                    ]
                },
                'withdrawals_l2_to_l1': {
                    'time': '~7 days',
                    'process': [
                        'Burn assets on L2',
                        'Include in batch',
                        'Generate zk-proof',
                        'Submit proof to L1',
                        'Finalization period',
                        'Claim assets on L1'
                    ]
                }
            },
            'third_party_bridges': {
                'availability': 'Multiple third-party bridge providers',
                'considerations': [
                    'Different security models',
                    'Varying withdrawal times',
                    'Different supported assets',
                    'Additional trust assumptions'
                ]
            }
        }

# Usage examples
analyzer = LineaRollupInfoAnalyzer('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY')

# Get basic rollup information
rollup_info = analyzer.get_rollup_info()
print("Basic Rollup Info:", json.dumps(rollup_info, indent=2))

# Get comprehensive status
comprehensive_status = analyzer.get_comprehensive_rollup_status()
print(f"\nNetwork: {comprehensive_status['network_info']['name']}")
print(f"Chain ID: {comprehensive_status['network_info']['chain_id']}")
print(f"Latest Block: {comprehensive_status['current_state']['latest_block']}")
print(f"Gas Utilization: {comprehensive_status['current_state']['gas_utilization']}%")

# Analyze network type
analysis = comprehensive_status['analysis']
print(f"\nRollup Type: {analysis['rollup_type']}")
print(f"Environment: {analysis['environment']}")
print("Key Features:")
for feature in analysis['key_features']:
    print(f"  - {feature}")

# Monitor performance (short demo)
print("\nStarting performance monitoring...")
performance_data = analyzer.monitor_rollup_performance(duration_minutes=2)
print("Performance Analysis:")
print(f"  Average block time: {performance_data['block_production']['average_block_time']}s")
print(f"  Health score: {performance_data['network_health']['health_score']}/100")

# Compare with L1
comparison = analyzer.compare_with_ethereum_l1()
print("\nLinea Advantages:")
for advantage in comparison['advantages_linea']:
    print(f"  - {advantage}")

# Governance analysis
governance = analyzer.analyze_upgradeability_governance()
print(f"\nGovernance Model: {governance['governance_model']['type']}")
print(f"Upgrade Process Duration: {governance['upgrade_process']['timeframes']['total_process']}")

# Bridge information
bridge_info = analyzer.get_bridge_integration_info()
print(f"\nBridge Withdrawal Time: {bridge_info['bridge_process']['withdrawals_l2_to_l1']['time']}")
print("Supported Assets:")
for asset in bridge_info['canonical_bridge']['supported_assets']:
    print(f"  - {asset}")
```

## Understanding Linea zkEVM Configuration

### Key Components

1. **Mode**: Operating mode of the rollup (zkEVM)
2. **Chain ID**: Network identifier (59144 for mainnet, 59140 for testnet)
3. **State Root**: Root hash of the current state tree
4. **Batch Commitment**: Commitment to the current batch of transactions
5. **Prover**: Address of the proof generation system
6. **Version**: Current version of the rollup implementation

### zkEVM Architecture

- **Proof System**: Zero-knowledge proofs validate transaction execution
- **Data Availability**: Transaction data posted to Ethereum L1
- **EVM Compatibility**: Full compatibility with Ethereum Virtual Machine
- **Finality**: Probabilistic finality on L2, cryptographic finality via proofs

## Common Use Cases

### 1. Network Health Monitoring

```javascript
// Monitor rollup health and performance
async function monitorRollupHealth(analyzer) {
  const healthCheck = async () => {
    const status = await analyzer.getComprehensiveRollupStatus();
    
    const alerts = [];
    
    // Check block production
    if (status.current_state.block_age_seconds > 300) {
      alerts.push({
        type: 'stale_blocks',
        severity: 'warning',
        message: 'Blocks are older than expected'
      });
    }
    
    // Check gas utilization
    if (status.current_state.gas_utilization > 95) {
      alerts.push({
        type: 'high_utilization',
        severity: 'info',
        message: 'Network experiencing high usage'
      });
    }
    
    return {
      status: alerts.length === 0 ? 'healthy' : 'warning',
      alerts: alerts,
      metrics: status.current_state
    };
  };
  
  return healthCheck;
}
```

### 2. Integration Compatibility Check

```python
def check_integration_compatibility(analyzer):
    """Check if current rollup config is compatible with integration"""
    
    status = analyzer.get_comprehensive_rollup_status()
    rollup_info = status['rollup_config']
    
    compatibility = {
        'evm_compatible': True,  # zkEVM is fully EVM compatible
        'supported_features': [
            'Standard Ethereum transactions',
            'Smart contract deployment',
            'ERC token standards',
            'Event emission and filtering',
            'eth_call and eth_estimateGas',
            'Debug and trace methods'
        ],
        'limitations': [
            'Proof generation delays for finality',
            'L1 data posting affects costs',
            'Bridge withdrawals require waiting period'
        ],
        'recommended_practices': [
            'Use standard Ethereum tooling',
            'Account for L1 fee components',
            'Plan for withdrawal delays',
            'Monitor gas price fluctuations'
        ]
    }
    
    return compatibility
```

### 3. Performance Benchmarking

```javascript
// Benchmark rollup performance characteristics
async function benchmarkRollupPerformance(analyzer) {
  const benchmark = {
    testDuration: '10 minutes',
    metrics: {},
    recommendations: []
  };
  
  // Monitor for performance data
  const performanceData = await analyzer.monitorRollupPerformance(10);
  
  benchmark.metrics = {
    avgBlockTime: performanceData.block_production.average_block_time,
    gasUtilization: performanceData.gas_utilization.average,
    healthScore: performanceData.network_health.health_score
  };
  
  // Generate recommendations
  if (benchmark.metrics.avgBlockTime > 15) {
    benchmark.recommendations.push(
      'Block times are longer than expected - monitor network congestion'
    );
  }
  
  if (benchmark.metrics.gasUtilization > 80) {
    benchmark.recommendations.push(
      'High gas utilization - consider transaction timing optimization'
    );
  }
  
  return benchmark;
}
```

## Integration Considerations

### Development

- **Tooling**: Use standard Ethereum development tools (Hardhat, Truffle, Remix)
- **RPC Compatibility**: Full JSON-RPC compatibility with additional rollup-specific methods
- **Gas Estimation**: Account for both L2 execution and L1 data posting costs

### Production Deployment

- **Security**: Leverage zkEVM's cryptographic security guarantees
- **Monitoring**: Monitor both L2 state and L1 proof submission
- **Bridge Integration**: Plan for canonical bridge usage and withdrawal delays

### User Experience

- **Transaction Speed**: Fast L2 confirmation with eventual L1 finality
- **Cost Optimization**: Optimize transaction data to minimize L1 costs
- **Bridge UX**: Clear communication about withdrawal timeframes

## Related Methods

- [`rollup_gasPrices`](https://www.dwellir.com/docs/linea/rollup_gasPrices) - Get gas price oracle data
- [`eth_chainId`](https://www.dwellir.com/docs/linea/eth_chainId) - Get network chain ID
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/linea/eth_getBlockByNumber) - Get block information

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Linea documentation](https://www.dwellir.com/docs/linea).*

---

## rpc_modules - Linea RPC Method

# rpc_modules - Linea RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Linea endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`rpc_modules` is useful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/linea/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/linea/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Linea RPC Method

# txpool_content - Linea RPC Method

Returns the full pending and queued transaction pool for the connected Linea endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`txpool_content` is useful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/linea/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/linea/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/linea/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Linea RPC Method

# txpool_status - Linea RPC Method

Returns transaction pool counters for the connected Linea endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`txpool_status` is valuable for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/linea/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/linea/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/linea/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Linea RPC Method

# web3_clientVersion - Linea RPC Method

Returns the current client software version string for your Linea node, including the client name, version number, OS, and runtime.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

## When to Use This Method

`web3_clientVersion` is valuable for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Linea client:', clientVersion);

// Using fetch
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Linea client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Linea client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/linea/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/linea/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/linea/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/linea/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Linea RPC Method

# web3_sha3 - Linea RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Linea.

> **Why Linea?** Build on Consensys-backed zkEVM L2 with $1B+ TVL and 807% growth in 2025 with 15-30x lower fees than Ethereum mainnet, 6,200 TPS throughput, SWIFT integration with 12+ institutions, and $725M Consensys backing.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for enterprise developers, DeFi builders, and teams seeking Consensys ecosystem integration:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/linea/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/linea/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/linea/web3_clientVersion) - Get node client version

---

## Lisk - Ethereum L2 Documentation

# Lisk - Ethereum L2 Documentation

## Lisk RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Lisk supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Lisk?

Lisk is the first Layer 1 to successfully transition to an Ethereum Layer 2, focusing on real-world applications in emerging markets. Built on Optimism's OP Stack, Lisk offers:

### **Optimized Performance**

- **2-second block times** - Fast transaction confirmations
- **10-100x lower costs** than Ethereum mainnet
- **Full EVM equivalence** - Deploy without modifications

### **Proven Security**

- **First L1 to L2 migration** - Successfully transitioned from Layer 1
- **Ethereum security** - Inherits L1 security guarantees via Optimism
- **OP Stack powered** - Built on battle-tested technology

### **Emerging Markets Focus**

- **Real-world assets (RWA)** - Specialized for tokenization
- **DePIN applications** - Decentralized physical infrastructure
- **High-growth markets** - Optimized for emerging economies

## Quick Start with Lisk

Connect to Lisk in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Lisk mainnet
const provider = new JsonRpcProvider(
  'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Lisk mainnet
const web3 = new Web3(
  'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Lisk:', chainId === 1135);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { lisk } from 'viem/chains';

// Create Lisk client
const client = createPublicClient({
  chain: lisk,
  transport: http('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 1135      | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | ETH       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Lisk supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods with L2 optimizations.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // L2 specific: Check L1 data availability
  if (receipt.l1Fee) {
    console.log('L1 data cost:', receipt.l1Fee);
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Lisk L2:

```javascript
// Estimate L2 execution gas
const l2Gas = await provider.estimateGas(tx);

// For L1 data fees on Lisk, fees are handled automatically
// Total gas cost includes both L2 execution and L1 data posting
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Lisk recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class BaseProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for transaction"

Lisk transactions require ETH for both L2 execution and L1 data availability:

```javascript
// Always account for total gas costs
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more ETH`);
}
```

### Error: "Transaction underpriced"

Lisk uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Lisk L2 requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Lisk)
const provider = new JsonRpcProvider(
  'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (1135)
// Note: Separate block numbers
// Note: L1 data fees apply
```

## Resources & Tools

### Official Resources

- [Lisk Documentation](https://docs.lisk.com)
- [Lisk Portal](https://portal.lisk.com)
- [Lisk Block Explorer](https://blockscout.lisk.com)

### Developer Tools

- [Hardhat Config](https://docs.lisk.com/tools/hardhat)
- [Foundry Setup](https://docs.lisk.com/tools/foundry)
- [Development Guide](https://docs.lisk.com/build)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Lisk with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - LISK RPC Method

# debug_traceBlock - LISK RPC Method

Traces all transactions in a block on LISK by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for LISK - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on LISK
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on LISK:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in LISK blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/lisk/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/lisk/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/lisk/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/lisk/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - LISK RPC Method

# debug_traceBlockByHash - LISK RPC Method

Traces all transactions in a block on LISK identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for LISK - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on LISK
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on LISK:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on LISK:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/lisk/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/lisk/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/lisk/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/lisk/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/lisk/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - LISK RPC Method

# debug_traceBlockByNumber - LISK RPC Method

Traces all transactions in a block on LISK identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for LISK - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of LISK execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on LISK:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on LISK:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/lisk/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/lisk/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/lisk/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/lisk/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - LISK RPC Method

# debug_traceCall - LISK RPC Method

Traces a call on LISK without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for LISK - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on LISK
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on LISK to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on LISK:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on LISK:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/lisk/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/lisk/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/lisk/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/lisk/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - LISK RPC Method

# debug_traceTransaction - LISK RPC Method

Traces a transaction execution on LISK by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on LISK
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/lisk/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/lisk/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - LISK RPC Method

# eth_accounts - LISK RPC Method

Returns a list of addresses owned by the client on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/lisk/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/lisk/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - LISK RPC Method

# eth_blockNumber - LISK RPC Method

Returns the number of the most recent block on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_blockNumber` is fundamental for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Syncing Applications** - Keep your dApp in sync with the latest LISK blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('LISK block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('LISK block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'LISK block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'LISK block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("LISK block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on LISK:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on LISK:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your LISK node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/lisk/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/lisk/eth_syncing) - Check if node is still syncing

---

## eth_call - LISK RPC Method

# eth_call - LISK RPC Method

Executes a new message call immediately without creating a transaction on LISK. Used for reading smart contract state.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

The `eth_call` method serves these key scenarios for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on LISK
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on LISK. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on LISK
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on LISK

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - LISK RPC Method

# eth_chainId - LISK RPC Method

Returns the chain ID used for transaction signing on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_chainId` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/lisk/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/lisk/eth_syncing) - Check sync status

---

## eth_coinbase - LISK RPC Method

# eth_coinbase - LISK RPC Method

Checks the legacy `eth_coinbase` compatibility method on LISK. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('LISK coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('LISK coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'LISK coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'LISK coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("LISK coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of LISK nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/lisk/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/lisk/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/lisk/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - LISK RPC Method

# eth_estimateGas - LISK RPC Method

Estimates the gas necessary to execute a transaction on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on LISK
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on LISK.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like LISK may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/lisk/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - LISK RPC Method

# eth_feeHistory - LISK RPC Method

Returns historical gas fee data on LISK, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on LISK without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on LISK.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on LISK) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/lisk/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/lisk/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - LISK RPC Method

# eth_gasPrice - LISK RPC Method

Returns the current gas price on LISK in wei.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on LISK
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of LISK. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on LISK, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on LISK: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if LISK supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/lisk/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/lisk/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - LISK RPC Method

# eth_getBalance - LISK RPC Method

Returns the balance of a given address on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getBalance` is fundamental for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Wallet applications**: Display user balances and enable balance-dependent operations on LISK
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to LISK
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on LISK. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} LISK`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on LISK at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 LISK')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 LISK')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on LISK.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/lisk/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/lisk/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - LISK RPC Method

# eth_getBlockByHash - LISK RPC Method

Returns information about a block by hash on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getBlockByHash` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on LISK
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the first L1-to-Superchain L2 focused on real-world assets and emerging markets
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on LISK.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the first L1-to-Superchain L2 focused on real-world assets and emerging markets.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on LISK.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/lisk/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - LISK RPC Method

# eth_getBlockByNumber - LISK RPC Method

Returns information about a block by block number on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getBlockByNumber` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on LISK
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the first L1-to-Superchain L2 focused on real-world assets and emerging markets

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on LISK with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on LISK. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the first L1-to-Superchain L2 focused on real-world assets and emerging markets expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/lisk/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/lisk/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/lisk/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - LISK RPC Method

# eth_getBlockReceipts - LISK RPC Method

Returns all transaction receipts for a block on LISK. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getBlockReceipts` is useful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for LISK, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on LISK. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the first L1-to-Superchain L2 focused on real-world assets and emerging markets, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x064ed396ec4bb9cd919f1ae9726064a32907a39da179a89fda4d094f0c0a89cf",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/lisk/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/lisk/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - LISK RPC Method

# eth_getCode - LISK RPC Method

Returns the bytecode at a given address on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getCode` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on LISK
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on LISK:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on LISK:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/lisk/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/lisk/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - LISK RPC Method

# eth_getFilterChanges - LISK RPC Method

Polls a filter on LISK for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getFilterChanges` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on LISK
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on LISK:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/lisk/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/lisk/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/lisk/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/lisk/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/lisk/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - LISK RPC Method

# eth_getFilterLogs - LISK RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on LISK. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getFilterLogs` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on LISK
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/lisk/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/lisk/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/lisk/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/lisk/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - LISK RPC Method

# eth_getLogs - LISK RPC Method

Returns an array of all logs matching a given filter object on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on LISK for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on LISK
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on LISK.

```javascript
const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if LISK enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on LISK, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/lisk/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/lisk/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - LISK RPC Method

# eth_getStorageAt - LISK RPC Method

Returns the value from a storage position at a given address on LISK. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getStorageAt` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **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 real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-lisk-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 = '0x4200000000000000000000000000000000000006'
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-lisk-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-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 LISK:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-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-lisk-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 = '0x4200000000000000000000000000000000000006';
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 LISK:`);
  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/lisk/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/lisk/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/lisk/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - LISK RPC Method

# eth_getTransactionByHash - LISK RPC Method

Returns the information about a transaction by transaction hash on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getTransactionByHash` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on LISK
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the first L1-to-Superchain L2 focused on real-world assets and emerging markets

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on LISK. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on LISK. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the first L1-to-Superchain L2 focused on real-world assets and emerging markets.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/lisk/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - LISK RPC Method

# eth_getTransactionCount - LISK RPC Method

Returns the number of transactions sent from an address on LISK, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getTransactionCount` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on LISK
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('LISK nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'LISK nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("LISK nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on LISK:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/lisk/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/lisk/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/lisk/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - LISK RPC Method

# eth_getTransactionReceipt - LISK RPC Method

Returns the receipt of a transaction by transaction hash on LISK. Receipt is only available for mined transactions.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_getTransactionReceipt` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on LISK and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the first L1-to-Superchain L2 focused on real-world assets and emerging markets by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on LISK. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on LISK, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the first L1-to-Superchain L2 focused on real-world assets and emerging markets. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the first L1-to-Superchain L2 focused on real-world assets and emerging markets
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc4ae02aa92a92ec161500444ec71945530760e062742f1745c0969a4fce864b9")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/lisk/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/lisk/eth_getLogs) - Query logs by filter

---

## eth_hashrate - LISK RPC Method

# eth_hashrate - LISK RPC Method

Returns the legacy `eth_hashrate` compatibility value on LISK. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('LISK hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('LISK hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'LISK hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'LISK hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("LISK hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/lisk/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/lisk/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/lisk/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - LISK RPC Method

# eth_maxPriorityFeePerGas - LISK RPC Method

Returns the current suggested priority fee (tip) per gas in wei on LISK. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on LISK
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('LISK priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'LISK priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("LISK priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on LISK:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on LISK:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/lisk/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/lisk/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/lisk/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - LISK RPC Method

# eth_mining - LISK RPC Method

Checks the legacy `eth_mining` compatibility method on LISK. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('LISK mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('LISK mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'LISK mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'LISK mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("LISK mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/lisk/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/lisk/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/lisk/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - LISK RPC Method

# eth_newBlockFilter - LISK RPC Method

Creates a filter on LISK that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_newBlockFilter` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Block Monitoring** - Detect new blocks on LISK as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on LISK:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/lisk/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/lisk/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/lisk/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/lisk/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - LISK RPC Method

# eth_newFilter - LISK RPC Method

Creates a filter object on LISK based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_newFilter` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Event Monitoring** - Subscribe to specific contract events on LISK such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on LISK:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/lisk/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/lisk/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/lisk/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/lisk/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/lisk/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - LISK RPC Method

# eth_newPendingTransactionFilter - LISK RPC Method

Creates a filter on LISK that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Mempool Monitoring** - Observe unconfirmed transactions on LISK to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for real-world asset tokenization, decentralized physical infrastructure (DePIN), and emerging market financial access

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on LISK...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on LISK:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/lisk/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/lisk/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/lisk/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - LISK RPC Method

# eth_protocolVersion - LISK RPC Method

Returns the current Ethereum protocol version used by the LISK node.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_protocolVersion` is useful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('LISK protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('LISK protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'LISK protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'LISK protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("LISK protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of LISK nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/lisk/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/lisk/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/lisk/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - LISK RPC Method

# eth_sendRawTransaction - LISK RPC Method

Submits a pre-signed transaction for broadcast to LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to LISK
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the LISK mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/lisk/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/lisk/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/lisk/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - LISK RPC Method

# eth_sendTransaction - LISK RPC Method

Creates and sends a new transaction from an unlocked account on LISK. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('LISK tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('LISK tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'LISK tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'LISK tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("LISK tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on LISK dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/lisk/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/lisk/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - LISK RPC Method

# eth_signTransaction - LISK RPC Method

Signs a transaction with the private key of the specified account on LISK without submitting it to the network.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed LISK tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed LISK tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed LISK tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on LISK:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/lisk/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/lisk/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/lisk/eth_accounts) - List accounts available for signing

---

## eth_syncing - LISK RPC Method

# eth_syncing - LISK RPC Method

Returns the sync status of your LISK node - either `false` when fully synced, or an object describing the sync progress.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_syncing` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('LISK node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('LISK node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("LISK node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/lisk/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/lisk/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/lisk/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/lisk/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - LISK RPC Method

# eth_uninstallFilter - LISK RPC Method

Removes a filter on LISK that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`eth_uninstallFilter` is important for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/lisk/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/lisk/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/lisk/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/lisk/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/lisk/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - LISK RPC Method

# net_listening - LISK RPC Method

Checks whether the connected LISK client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`net_listening` is useful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('LISK node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'LISK node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("LISK node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/lisk/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/lisk/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/lisk/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/lisk/web3_clientVersion) - Get node client info

---

## net_peerCount - LISK RPC Method

# net_peerCount - LISK RPC Method

Returns the number of peers currently connected to your LISK node.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`net_peerCount` is important for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific LISK deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`LISK peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'LISK peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("LISK peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of LISK nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/lisk/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/lisk/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/lisk/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/lisk/web3_clientVersion) - Get node client info

---

## net_version - LISK RPC Method

# net_version - LISK RPC Method

Returns the current network ID on LISK as a decimal string. The network ID identifies which network the node is connected to.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`net_version` is essential for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Endpoint Identification** - Confirm your application is connected to the expected LISK network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('LISK network ID:', networkId);

// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'LISK network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("LISK network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/lisk/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/lisk/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/lisk/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/lisk/eth_syncing) - Check node sync progress

---

## rpc_modules - LISK RPC Method

# rpc_modules - LISK RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected LISK endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`rpc_modules` is useful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/lisk/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/lisk/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - LISK RPC Method

# web3_clientVersion - LISK RPC Method

Returns the current client software version string for your LISK node, including the client name, version number, OS, and runtime.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

## When to Use This Method

`web3_clientVersion` is valuable for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('LISK client:', clientVersion);

// Using fetch
const response = await fetch('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'LISK client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("LISK client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/lisk/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/lisk/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/lisk/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/lisk/net_peerCount) - Get number of connected peers

---

## web3_sha3 - LISK RPC Method

# web3_sha3 - LISK RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on LISK.

> **Why LISK?** Build on the first L1-to-Superchain L2 focused on real-world assets and emerging markets with OP Stack Superchain integration, Gelato rollup-as-a-service, 500K OP grant, and LSK token migration from L1.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for RWA developers, DePIN builders, and teams targeting Southeast Asia and Africa markets:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-lisk-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/lisk/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/lisk/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/lisk/web3_clientVersion) - Get node client version

---

## Manta Atlantic - ZK Identity L1 Guide

# Manta Atlantic - ZK Identity L1 Guide

## Manta Atlantic RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Manta Atlantic supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Manta Atlantic?

- **Fastest zk Layer 1 on Polkadot** – Atlantic specializes in zero-knowledge identity proofs with high-throughput circuits powering zkSoulbound credentials for millions of users.
- **Programmable privacy-preserving identities** – zkSBTs, selective disclosure primitives, and proof tooling let teams ship compliant identity workflows without exposing raw user data.
- **On-chain compliance infrastructure** – The NPO (NFT Private Offering) stack supports private KYC/AML verification, credential revocation, and auditable reporting for regulated deployments.
- **Interoperability across Polkadot** – As parachain 2104, Atlantic inherits shared security, XCMP messaging, and bridges into ecosystems like Moonbeam, Bifrost, and Ethereum.

## Quick Start with Manta Atlantic

Connect to Atlantic's production archive endpoint (no public testnet) using your Dwellir API key:

Replace `YOUR_API_KEY` after you [create an account](https://dashboard.dwellir.com/register). The WebSocket endpoint is available at `wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY`.

### Connect with @polkadot/api

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Confirm network metadata
const chain = await api.rpc.system.chain();
console.log(`Connected to ${chain.toString()}`);

// Fetch the latest finalized block
const latest = await api.rpc.chain.getBlock();
console.log('Finalized block number', latest.block.header.number.toNumber());
```

### Rust (subxt) bootstrap

```rust
use subxt::{config::polkadot::PlainConfig, OnlineClient};

#[subxt::subxt(runtime_metadata_url = "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")]
pub mod manta_atlantic {}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
 let api = OnlineClient::<PlainConfig>::from_url(
 "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
 ).await?;

 let runtime = api.runtime_version().await?;
 println!("Spec version: {}", runtime.spec_version);

 Ok(())
}
```

## Network Information

| Parameter          | Value              | Details                                         |
| ------------------ | ------------------ | ----------------------------------------------- |
| Parachain ID       | 2104               | Registered on Polkadot Relay Chain              |
| Consensus          | NPoS + zk circuits | Collators submit zk-validated state proofs      |
| Average Block Time | ≈ 13.3 seconds     | Measured 7-day mean on Polkadot OpenGov metrics |
| Native Token       | MANTA              | Used for staking, fees, and collator bonds      |

### Operational Notes

| Parameter           | Value                                                  | Details                                                                            |
| ------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| Active Collators    | 54                                                     | Securing 101.8M staked MANTA with GRANDPA finality on top of zk-verified execution |
| Observed Block Time | \~13.35 seconds                                        | Based on PublicNode telemetry over the last seven days                             |
| Collator Bond       | 400,000 MANTA                                          | Rewards come from a 2% annual inflation stream dedicated to parachain security     |
| Staking Cadence     | 6-hour rounds                                          | 7-day unbonding period for predictable uptime incentives                           |
| Throughput Roadmap  | Asynchronous backing targets 6-second parachain blocks | Depends on host-chain optimizations rolling out                                    |

## API Reference

Atlantic exposes the full Substrate JSON-RPC surface, including `chain_*`, `state_*`, and `author_*` namespaces for block data, storage access, and extrinsic submission.

| Category | Key Methods                                          | Use Cases                                                                |
| -------- | ---------------------------------------------------- | ------------------------------------------------------------------------ |
| Chain    | `chain_getBlock`, `chain_getFinalizedHead`           | Retrieve zk-anchored parachain blocks and finality proofs                |
| State    | `state_getStorage`, `state_getRuntimeVersion`        | Inspect identity pallets, zk credential registries, and runtime metadata |
| Author   | `author_submitExtrinsic`, `author_pendingExtrinsics` | Submit zkSBT transactions and monitor queue health                       |

### Sample cURL call

```bash
curl https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
 -H 'Content-Type: application/json' \
 -d '{
 "jsonrpc": "2.0",
 "method": "chain_getBlock",
 "params": [],
 "id": 1
 }'
```

Explore detailed method docs in the [RPC reference](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock).

## Privacy Features Overview

- **zkSBTs for regulated identity** – Issue, revoke, and expire credentials privately using Manta’s zkSBT runtime modules and Prove Keys for selective disclosure.
- **Programmable identity fabric** – Compose verifiable credentials, attestations, and session keys tied to zk addresses for multi-jurisdictional compliance.
- **Privacy-preserving credential analytics** – Aggregate issuance stats and revocation logs without exposing user PII, using off-chain indexers that consume hashed commitments.

Deep dives:

- [Zero-Knowledge Soulbound Tokens](https://www.dwellir.com/docs/manta-atlantic/privacy/zksbt_overview)
- [Programmable Identities](https://www.dwellir.com/docs/manta-atlantic/privacy/programmable_identities)
- [Compliance Infrastructure](https://www.dwellir.com/docs/manta-atlantic/privacy/compliance_infrastructure)
- [zkAddress System](https://www.dwellir.com/docs/manta-atlantic/privacy/zkaddress_system)

## zkAddress System

Atlantic assigns every participant a standard Substrate account **and** a shielded UTXO-style address, enabling private balance updates while maintaining compatibility with Polkadot tooling.

- Establishes confidentiality via one-time addresses and viewing keys while preserving interoperability with public XCMP channels.
- Selective disclosure relies on user-controlled Prove Keys so only authorized verifiers can inspect credential proofs.

## Compliance Tools

- **zkKYC verification** – Issuers attest to KYC completion without storing underlying documents on-chain, satisfying policy requirements for permissioned DeFi.
- **Audit-friendly reporting** – Regulators receive revocation or expiry events derived from zk commitments, rather than raw identity data.
- **Bridges to off-chain capital markets** – Bifrost and other parachains integrate Atlantic credentials to wrap staking positions (vMANTA) and unlock liquidity while preserving privacy.

## Development Guides

1. **Issue zkSBTs** – Follow the [minting guide](https://www.dwellir.com/docs/manta-atlantic/privacy/zksbt_overview) to register issuers, define schemas, and broadcast credential extrinsics.
2. **Build programmable identity flows** – Combine zkAddress guardrails with session-based Prove Keys to create reusable identity vaults.
3. **Integrate compliance pipelines** – Map `identity_verifyCredential` RPC calls to your policy engine for real-time access control.

## Troubleshooting

- **Proof generation stalls** – Re-sync proving key material and confirm `zk_generateProof` inputs match runtime-cached schema hashes.
- **Credential verification failures** – Ensure the verifier holds the latest Prove Key rotation and that revocation registries are in sync via `state_getStorage`.
- **Cross-chain settlement delays** – Monitor collator liveness (6-hour nomination cycles) and confirm asynchronous backing slots are available before submitting high-value transfers.

## Resources & Tools

- **Manta Atlantic Docs** – Official zkSBT, zkAddress, and Prove Key specifications.
- **Manta Network State of the Network (Q1 2025)** – Collator metrics, staking economics, and deprecation roadmap through July 2026.
- **MANTA Staking Guide** – How-to for nominators, collators, and reward cycles.
- **Messari Protocol Overview** – Historical issuance data and compliance-focused adoption metrics.
- **Substrate JSON-RPC Spec** – Authoritative method definitions for `chain_*`, `state_*`, and `author_*`.

Ready to build? [Get your API key](https://dashboard.dwellir.com/register) and start integrating Manta Atlantic today.

---

## author_pendingExtrinsics - Manta Atlantic RPC Method

# author_pendingExtrinsics - Manta Atlantic RPC Method

Returns all pending extrinsics currently in the transaction pool on Manta Atlantic. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`author_pendingExtrinsics` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Manta Atlantic
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Manta Atlantic transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/manta-atlantic/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/manta-atlantic/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/manta-atlantic/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Manta Atlantic RPC Method

# author_rotateKeys - Manta Atlantic RPC Method

Generate a new set of session keys on Manta Atlantic. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`author_rotateKeys` is critical for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Validator Setup** - Generate initial session keys when setting up a new validator on private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Manta Atlantic:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/manta-atlantic/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/manta-atlantic/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Manta Atlantic RPC Method

# author_submitAndWatchExtrinsic - Manta Atlantic RPC Method

Submits a signed extrinsic to Manta Atlantic and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Manta Atlantic
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/manta-atlantic/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/manta-atlantic/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/manta-atlantic/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Manta Atlantic RPC Method

# author_submitExtrinsic - Manta Atlantic RPC Method

Submits a fully signed extrinsic to Manta Atlantic for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`author_submitExtrinsic` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Token Transfers** -- Send native tokens or assets between accounts on Manta Atlantic
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/manta-atlantic/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/manta-atlantic/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Manta Atlantic RPC Method

# beefy_getFinalizedHead - Manta Atlantic RPC Method

Returns the block hash of the latest BEEFY-finalized block on Manta Atlantic. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`beefy_getFinalizedHead` is important for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/manta-atlantic/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Manta Atlantic RPC Method

# chain_getBlock - Manta Atlantic RPC Method

Retrieves complete block information from Manta Atlantic, including the block header, extrinsics, and justifications.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/manta-atlantic/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Manta Atlantic RPC Method

# chain_getBlockHash - Manta Atlantic RPC Method

Returns the block hash for a given block number on Manta Atlantic. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`chain_getBlockHash` is fundamental for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Manta Atlantic
- **Block Navigation** - Navigate the blockchain history for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Manta Atlantic
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Manta Atlantic for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Manta Atlantic state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Manta Atlantic network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/manta-atlantic/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Manta Atlantic RPC Method

# chain_getFinalizedHead - Manta Atlantic RPC Method

Returns the hash of the last finalized block on Manta Atlantic. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`chain_getFinalizedHead` is critical for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Manta Atlantic
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Manta Atlantic:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/manta-atlantic/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Manta Atlantic RPC Method

# chain_getHeader - Manta Atlantic RPC Method

Returns the block header for a given hash on Manta Atlantic. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`chain_getHeader` is ideal for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Manta Atlantic
- **Chain Synchronization** - Track block production and monitor chain progress for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Manta Atlantic:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Manta Atlantic chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Manta Atlantic block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Manta Atlantic RPC Method

# chain_subscribeFinalizedHeads - Manta Atlantic RPC Method

Subscribe to receive notifications when blocks are finalized on Manta Atlantic. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Exchange Deposits** - Only credit funds after finalization for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Manta Atlantic:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/manta-atlantic/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Manta Atlantic RPC Method

# chain_subscribeNewHeads - Manta Atlantic RPC Method

Subscribe to receive notifications when new block headers are produced on Manta Atlantic. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`chain_subscribeNewHeads` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Block Monitoring** - Track new blocks in real time on Manta Atlantic for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Manta Atlantic as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Manta Atlantic:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/manta-atlantic/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Manta Atlantic RPC Method

# grandpa_roundState - Manta Atlantic RPC Method

Returns the state of the current GRANDPA finality round on Manta Atlantic when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`grandpa_roundState` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Manta Atlantic, critical for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/manta-atlantic/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/manta-atlantic/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Manta Atlantic RPC Method

# payment_queryFeeDetails - Manta Atlantic RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Manta Atlantic. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`payment_queryFeeDetails` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Manta Atlantic
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/manta-atlantic/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/manta-atlantic/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/manta-atlantic/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/manta-atlantic/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Manta Atlantic RPC Method

# payment_queryInfo - Manta Atlantic RPC Method

Estimates the fee for an encoded extrinsic on Manta Atlantic. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`payment_queryInfo` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Manta Atlantic
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/manta-atlantic/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/manta-atlantic/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/manta-atlantic/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/manta-atlantic/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## Compliance Infrastructure

# Compliance Infrastructure

Manta Atlantic provides a full-stack compliance toolkit: zkSBT credentials, verifier keys, and reporting channels that satisfy regulatory needs without leaking personal data.

## Private KYC/AML

- **KYC attestations** – Issuers publish zk proofs confirming identity verification; verifiers only see proof validity, not raw documents.
- **AML screening** – Credential schemas incorporate sanctions or risk flags that can be checked via `identity_verifyCredential` during transaction authorization.
- **Revocation** – Nullifiers revoke credentials instantly, ensuring revoked users cannot pass future checks.

## Reporting & Auditing

| Requirement            | Atlantic Capability                                                              | Notes                                                    |
| ---------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------- |
| Regulator visibility   | Access aggregated issuance and revocation metrics without identity leakage.      | Aligns with NPO reporting flows for enterprise partners. |
| Proof of compliance    | Share verifier logs demonstrating successful zk checks, signed with issuer keys. | Works with Prove Key distribution model.                 |
| Lifecycle transparency | Track credential status via `state_getStorage` queries on registry pallets.      | Integrate into SOC2 or ISO audit evidence bundles.       |

## Operational Controls

1. **Issuer governance** – Participate in network governance to stay aligned with Atlantic’s deprecation plan and runtime upgrades.
2. **Staking economics** – Collator incentives (2% inflation, 6-hour payout cadence) prioritize availability required for compliance workloads.
3. **Disaster recovery** – Maintain off-chain backups of Prove Keys and witness generators; Atlantic’s zk circuits can regenerate proofs if keys rotate.

## Integration Playbook

- Map each compliance policy to a credential schema (e.g., KYC Tier 2, Accredited Investor) and automate issuance via CI pipelines.
- Use asynchronous backing-aware monitoring to ensure block production throughput before onboarding large partners.
- Coordinate with bridging partners such as Bifrost to wrap compliant positions (vMANTA) while preserving privacy guarantees.

Next up: understand the [zkAddress System](https://www.dwellir.com/docs/manta-atlantic/privacy/zkaddress_system) for private settlement flows.

---

## Programmable Identities

# Programmable Identities

Manta Atlantic combines zkAddresses, zkSBTs, and selective disclosure keys to let builders compose identity systems that bridge on-chain compliance with user-centric privacy.

## Core Building Blocks

- **zkAddress pairs** – Every participant controls a public Substrate account plus a shielded address for confidential asset and credential management.
- **Prove Keys** – Holders distribute verification keys to specific relying parties, enabling selective KYC disclosure without exposing global viewing access.
- **Programmable schemas** – Issuers encode logic for membership, accreditation, jurisdiction, or AML flags, then publish updates via runtime governance.

## Identity Vault Pattern

1. **Bootstrap** – Derive zkAddresses for each user and link them to public accounts through encrypted off-chain registries.
2. **Credential orchestration** – Automate zkSBT issuance on approval events (KYC pass, accreditation, residency confirmation).
3. **Session management** – Rotate Prove Keys per relying party and attach policy metadata (expiry, scope, revocation callbacks).
4. **Audit hooks** – Stream anonymized issuance metrics to monitoring stacks for compliance reporting.

## Cross-Chain Portability

- Atlantic credentials travel to other Polkadot parachains through XCMP, unlocking composability with DeFi venues such as Bifrost’s vMANTA staking derivatives.
- Identity payloads can also bridge to EVM ecosystems (e.g., Moonbeam, Ethereum) using Manta’s interoperability hubs, preserving privacy across domains.

## Policy-Driven Verification

| Requirement       | Implementation Strategy                                                                                                                                                         |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Geographic access | Encode jurisdiction attributes inside credential schema and check using `identity_verifyCredential`, which wraps the zk verification flow described in the NPO compliance docs. |
| Transaction caps  | Track credential usage counts off-chain and rotate Prove Keys when session budgets are exhausted.                                                                               |
| AML monitoring    | Subscribe to revocation events and apply business rules before processing settlement.                                                                                           |

## Governance & Roadmap

- Manta Atlantic is scheduled for deprecation in July 2026; plan migrations to successor deployments while leveraging Atlantic for near-term compliance projects.
- Participation in staking/governance keeps credential issuers aligned with network updates that may alter identity pallet semantics.

Proceed to [Compliance Infrastructure](https://www.dwellir.com/docs/manta-atlantic/privacy/compliance_infrastructure) for regulatory workflows.

---

## zkAddress System

# zkAddress System

Manta Atlantic augments traditional Substrate accounts with shielded zkAddresses so users can transact privately while retaining compatibility with Polkadot tooling.

## Dual-Address Model

- **Public account** – Handles staking, governance, and XCMP interactions using standard Polkadot keys.
- **Private zkAddress** – Holds UTXO-style notes that represent balances, credentials, or proofs, enabling confidential transfers and credential issuance.

## Key Concepts

| Component       | Purpose                                                                                                              |
| --------------- | -------------------------------------------------------------------------------------------------------------------- |
| Viewing Key     | Lets holders inspect their private note set locally without revealing it to the network.                             |
| Prove Key       | Grants third parties the ability to verify specific proofs, supporting selective disclosure in compliance workflows. |
| Note Commitment | Binds balances or credentials to zkAddresses using commitments stored in Atlantic’s runtime.                         |

## Private Transaction Flow

1. **Note creation** – Sender generates a new commitment and encrypts the payload with the recipient’s viewing key.
2. **Proof generation** – Sender calls `zk_generateProof` to produce a zero-knowledge proof of validity without revealing note contents.
3. **Submission** – The proof and ciphertext are broadcast via extrinsic or RPC, updating the UTXO set while keeping balances hidden.
4. **Consumption** – Recipient scans encrypted updates, decrypts matching notes, and updates their local wallet state.

## Interoperability

- zkAddresses can export proofs to partner chains (e.g., Bifrost, Moonbeam) to unlock wrapped liquidity without disclosing identities.
- Polkadot asynchronous backing keeps private transfers within expected latency bounds even during high throughput periods.

## Operational Tips

- Rotate Prove Keys regularly and record distribution logs to maintain auditability.
- Cache circuit parameters locally to avoid latency spikes in proof generation services.
- Monitor `state_getStorage` for note commitment merkle roots to keep client state synchronized.

For RPC invocation details, refer to the Manta Atlantic documentation.

---

## zkSBT Overview

# zkSBT Overview

Manta Atlantic’s zkSBT framework lets issuers attest to real-world identity or compliance checks without ever exposing the underlying documents on-chain.

## Why zkSBTs Matter

- **Private attestations** – zkSBT proofs encode that requirements (KYC, accreditation, residency) have been met while leaking no raw attributes.
- **Programmable lifecycle** – Issuers can define expiry, revocation conditions, and delegation policies enforced by runtime modules.
- **Adoption at scale** – Over 1.16 million zkSBTs have been minted for 1.5+ million Web3 users, demonstrating production readiness.

## Architecture

1. **Schema registry** – Issuers register credential schemas that define statement circuits and commitment formats.
2. **Witness generation** – Sensitive data stays off-chain; issuers compute witnesses locally and generate Groth16 proofs compatible with Atlantic’s circuits.
3. **zkSBT pallet** – Proofs are submitted as extrinsics, minting non-transferable tokens bound to a user’s zkAddress commitment.
4. **Selective disclosure** – Holders derive viewing access with Prove Keys so verifiers can validate claims without deanonymizing accounts.

## Issuance Workflow

1. **Register issuer keys** – Broadcast an extrinsic to enrol your issuer DID and publishing key.
2. **Publish schema** – Commit schema metadata (description, constraint hash, revocation type).
3. **Generate proof** – Use the trusted setup artifacts to compute a zk proof tied to the recipient’s zkAddress commitment.
4. **Submit `sbt_mintPrivate`** – Call the RPC (or runtime extrinsic) with the proof, note, and expiry metadata.
5. **Distribute Prove Keys** – Share verification keys with relying parties via secure out-of-band channels.

## Revocation & Compliance

- **Revocation lists** – Issuers can revoke credentials by publishing nullifiers; verifiers check revocation registries during proof verification.
- **Expiry logic** – zkSBTs include timestamps so expired credentials fail verification automatically.
- **Audit trails** – Regulators can audit aggregate issuance and revocation counts without linking to individual identities.

## Integration Checklist

- Sync the latest proving and verification keys from the official repositories.
- Monitor revocation registries via `state_getStorage` to invalidate stale credentials quickly.
- Store credential metadata in encrypted vaults; only commitments and nullifiers hit the chain.
- Automate issuance with CI pipelines so every new compliance approval emits a zkSBT mint.

Next: implement the workflow end-to-end in [Programmable Identities](https://www.dwellir.com/docs/manta-atlantic/privacy/programmable_identities).

---

## rpc_methods - Manta Atlantic RPC Method

# rpc_methods - Manta Atlantic RPC Method

Returns a list of all RPC methods exposed by the Manta Atlantic node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`rpc_methods` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Manta Atlantic node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Manta Atlantic endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Manta Atlantic endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/manta-atlantic/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/manta-atlantic/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Manta Atlantic RPC Method

# state_call - Manta Atlantic RPC Method

Calls a runtime API function on Manta Atlantic and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`state_call` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/manta-atlantic/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/manta-atlantic/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/manta-atlantic/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) -- Get the node version for compatibility checking

---

## state_getKeysPaged - Manta Atlantic RPC Method

# state_getKeysPaged - Manta Atlantic RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Manta Atlantic. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`state_getKeysPaged` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Manta Atlantic
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/manta-atlantic/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/manta-atlantic/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Manta Atlantic RPC Method

# state_getMetadata - Manta Atlantic RPC Method

Returns the runtime metadata for Manta Atlantic as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`state_getMetadata` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Manta Atlantic
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Manta Atlantic:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Manta Atlantic:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/manta-atlantic/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/manta-atlantic/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Manta Atlantic RPC Method

# state_getRuntimeVersion - Manta Atlantic RPC Method

Returns the runtime version information for Manta Atlantic, including the spec name, spec version, implementation version, and supported API versions.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`state_getRuntimeVersion` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Manta Atlantic
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Manta Atlantic in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/manta-atlantic/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Manta Atlantic RPC Method

# state_getStorage - Manta Atlantic RPC Method

Returns the SCALE-encoded storage value for a given key on Manta Atlantic. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`state_getStorage` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Manta Atlantic
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/manta-atlantic/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/manta-atlantic/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Manta Atlantic RPC Method

# state_queryStorageAt - Manta Atlantic RPC Method

Queries multiple storage keys at a specific block on Manta Atlantic, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`state_queryStorageAt` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Manta Atlantic
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/manta-atlantic/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/manta-atlantic/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/manta-atlantic/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/manta-atlantic/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Manta Atlantic RPC Method

# system_chain - Manta Atlantic RPC Method

Returns the chain name of the Manta Atlantic network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`system_chain` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Network Verification** -- Confirm your application is connected to the correct Manta Atlantic network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Manta Atlantic"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', 'Manta Atlantic');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/manta-atlantic/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/manta-atlantic/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/manta-atlantic/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/manta-atlantic/rpc_methods) -- List all available RPC methods

---

## system_health - Manta Atlantic RPC Method

# system_health - Manta Atlantic RPC Method

Returns the health status of the Manta Atlantic node, including peer count, sync state, and whether the node expects to have peers.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`system_health` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Manta Atlantic
- **Load Balancing** - Route requests only to healthy, fully synced nodes for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Manta Atlantic:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Manta Atlantic nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/manta-atlantic/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Manta Atlantic RPC Method

# system_name - Manta Atlantic RPC Method

Returns the node implementation name on Manta Atlantic. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`system_name` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Manta Atlantic
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Manta Atlantic node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Manta Atlantic node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Manta Atlantic node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Manta Atlantic node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Manta Atlantic node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Manta Atlantic nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/manta-atlantic/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/manta-atlantic/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/manta-atlantic/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/manta-atlantic/rpc_methods) -- List all available RPC methods

---

## system_properties - Manta Atlantic RPC Method

# system_properties - Manta Atlantic RPC Method

Returns the chain-specific properties for Manta Atlantic, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`system_properties` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Manta Atlantic
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/manta-atlantic/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/manta-atlantic/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/manta-atlantic/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/manta-atlantic/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/manta-atlantic/rpc_methods) -- List all available RPC methods

---

## system_version - Manta Atlantic RPC Method

# system_version - Manta Atlantic RPC Method

Returns the node implementation version string on Manta Atlantic. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Manta Atlantic?** Build on the ZK Layer 1 on Polkadot enabling private transactions and on-chain compliance identities with zkSNARK-powered privacy, modular compliance identities, MANTA token staking hub, and end-to-end transaction privacy.

## When to Use This Method

`system_version` is essential for privacy-focused developers, DeFi builders requiring private swaps, and teams needing zkSNARK capabilities:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Manta Atlantic
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for private asset transfers, zkNFTs, on-chain compliance identities, and private parachain asset swaps
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Manta Atlantic node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Manta Atlantic node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Manta Atlantic node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Manta Atlantic node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-manta-atlantic-mainnet.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Manta Atlantic node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Manta Atlantic nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/manta-atlantic/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/manta-atlantic/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/manta-atlantic/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/manta-atlantic/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/manta-atlantic/rpc_methods) -- List all available RPC methods

---

## Manta Pacific - EVM Network Guide

# Manta Pacific - EVM Network Guide

## Manta Pacific RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Manta Pacific supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Manta Pacific?

Focus on building. Dwellir delivers:

- High‑availability RPC with global anycast routing and low latency
- Full Ethereum JSON‑RPC coverage with tracing and debug APIs
- Consistent, high‑throughput mainnet endpoints
- Clear rate limits, observability, and an enterprise‑grade SLA

## Quick Start with Manta Pacific

Connect to Manta Pacific in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Manta Pacific mainnet
const provider = new JsonRpcProvider(
  'https://api-manta-pacific-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Manta Pacific mainnet
const web3 = new Web3(
  'https://api-manta-pacific-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Manta Pacific:', chainId === 169);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';

// Create client (without predefined chain)
const client = createPublicClient({
  transport: http('https://api-manta-pacific-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value    | Details      |
| ------------ | -------- | ------------ |
| Chain ID     | 169      | Mainnet      |
| RPC Standard | Ethereum | JSON-RPC 2.0 |

## API Reference

Manta Pacific supports the standard Ethereum JSON-RPC 2.0 API. Access common methods for blocks, transactions, logs, traces, and debugging.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);
  return receipt;
}
```

### Gas Optimization

Use EIP‑1559 dynamic fees for predictable pricing:

```javascript
const feeData = await provider.getFeeData();
const tx = {
  to: '0x...',
  value: 0n,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n,
};
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Manta Pacific recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class Manta PacificProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-manta-pacific-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds"

Always check the account balance against the estimated gas cost:

```javascript
const balance = await provider.getBalance(address);
const gas = await provider.estimateGas(tx);
const maxCost = gas * (tx.maxFeePerGas ?? 0n) + (tx.value ?? 0n);
if (balance < maxCost) throw new Error('Insufficient funds');
```

### Error: "Transaction underpriced"

Manta Pacific uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Manta Pacific L2 requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Manta Pacific)
const provider = new JsonRpcProvider(
  'https://api-manta-pacific-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (169)
// Note: Separate block numbers
```

## Resources & Tools

### Official Resources

- Official docs, explorer, and tooling: please refer to the Manta Pacific official channels.

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Manta Pacific with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Manta RPC Method

# debug_traceBlock - Manta RPC Method

Traces all transactions in a block on Manta Pacific by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Manta Pacific - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Manta
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Manta:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Manta blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/manta-pacific/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/manta-pacific/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Manta RPC Method

# debug_traceBlockByHash - Manta RPC Method

Traces all transactions in a block on Manta Pacific identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Manta Pacific - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Manta
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Manta:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Manta:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/manta-pacific/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/manta-pacific/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Manta RPC Method

# debug_traceBlockByNumber - Manta RPC Method

Traces all transactions in a block on Manta Pacific identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Manta Pacific - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Manta execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Manta:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Manta:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/manta-pacific/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/manta-pacific/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Manta RPC Method

# debug_traceCall - Manta RPC Method

Traces a call on Manta Pacific without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Manta Pacific - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Manta
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "data": "0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
        "data": "0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
        "data": "0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    data: '0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    data: '0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    'data': '0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
        "data": "0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Manta to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Manta:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Manta:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/manta-pacific/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/manta-pacific/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Manta RPC Method

# debug_traceTransaction - Manta RPC Method

Traces a transaction execution on Manta Pacific by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Manta
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/manta-pacific/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Manta RPC Method

# eth_accounts - Manta RPC Method

Returns a list of addresses owned by the client on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for ZK application developers, privacy-focused builders, and teams requiring modular scalability in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/manta-pacific/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Manta RPC Method

# eth_blockNumber - Manta RPC Method

Returns the number of the most recent block on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_blockNumber` is fundamental for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Syncing Applications** - Keep your dApp in sync with the latest Manta blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Manta block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Manta block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Manta block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Manta block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Manta block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Manta:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Manta:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Manta node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/manta-pacific/eth_syncing) - Check if node is still syncing

---

## eth_call - Manta RPC Method

# eth_call - Manta RPC Method

Executes a new message call immediately without creating a transaction on Manta Pacific. Used for reading smart contract state.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

The `eth_call` method serves these key scenarios for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Manta
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';
const walletAddress = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Manta. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Manta
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Manta Pacific

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "data": "0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "data": "0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    data := common.FromHex("0x70a082310000000000000000000000000Dc808adcE2099A9F62AA87D9670745AbA741746")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Manta RPC Method

# eth_chainId - Manta RPC Method

Returns the chain ID used for transaction signing on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_chainId` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/manta-pacific/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/manta-pacific/eth_syncing) - Check sync status

---

## eth_coinbase - Manta RPC Method

# eth_coinbase - Manta RPC Method

Checks the legacy `eth_coinbase` compatibility method on Manta Pacific. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for ZK application developers, privacy-focused builders, and teams requiring modular scalability when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Manta coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Manta coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Manta coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Manta coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Manta coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Manta nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/manta-pacific/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/manta-pacific/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/manta-pacific/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Manta RPC Method

# eth_estimateGas - Manta RPC Method

Estimates the gas necessary to execute a transaction on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Manta
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x0Dc808adcE2099A9F62AA87D9670745AbA741746', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x0Dc808adcE2099A9F62AA87D9670745AbA741746', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Manta.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Manta may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "to": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x0Dc808adcE2099A9F62AA87D9670745AbA741746', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/manta-pacific/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Manta RPC Method

# eth_feeHistory - Manta RPC Method

Returns historical gas fee data on Manta Pacific, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Manta without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Manta.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Manta) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/manta-pacific/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/manta-pacific/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Manta RPC Method

# eth_gasPrice - Manta RPC Method

Returns the current gas price on Manta Pacific in wei.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Manta
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Manta. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Manta, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Manta: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Manta supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/manta-pacific/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/manta-pacific/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Manta RPC Method

# eth_getBalance - Manta RPC Method

Returns the balance of a given address on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getBalance` is fundamental for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Manta
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Manta Pacific
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Manta Pacific. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Manta`);
  return balance;
}

displayBalance('0x0Dc808adcE2099A9F62AA87D9670745AbA741746');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Manta at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Manta')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Manta')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Manta Pacific.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/manta-pacific/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Manta RPC Method

# eth_getBlockByHash - Manta RPC Method

Returns information about a block by hash on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getBlockByHash` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Manta Pacific
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Manta Pacific.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Manta Pacific.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Manta RPC Method

# eth_getBlockByNumber - Manta RPC Method

Returns information about a block by block number on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getBlockByNumber` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Manta Pacific
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Manta Pacific with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Manta Pacific. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Manta RPC Method

# eth_getBlockReceipts - Manta RPC Method

Returns all transaction receipts for a block on Manta Pacific. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getBlockReceipts` is useful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Manta Pacific, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Manta Pacific. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xd40eb9063e1311e2c49869e91d4033d24e7d82620a2c305247ac4d0587757a3c",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Manta RPC Method

# eth_getCode - Manta RPC Method

Returns the bytecode at a given address on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getCode` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Manta
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Manta:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Manta:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/manta-pacific/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/manta-pacific/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Manta RPC Method

# eth_getFilterChanges - Manta RPC Method

Polls a filter on Manta Pacific for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getFilterChanges` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Manta
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Manta:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/manta-pacific/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Manta RPC Method

# eth_getFilterLogs - Manta RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Manta Pacific. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getFilterLogs` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Manta
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/manta-pacific/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Manta RPC Method

# eth_getLogs - Manta RPC Method

Returns an array of all logs matching a given filter object on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Manta for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Manta Pacific
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Manta.

```javascript
const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Manta enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Manta Pacific, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Manta RPC Method

# eth_getStorageAt - Manta RPC Method

Returns the value from a storage position at a given address on Manta Pacific. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getStorageAt` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **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 ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **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": [
    "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "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-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x0Dc808adcE2099A9F62AA87D9670745AbA741746', '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-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';

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-manta-pacific-archive.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 = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
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-manta-pacific-archive.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-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    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 Manta:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.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-manta-pacific-archive.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 = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';
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 Manta:`);
  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/manta-pacific/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/manta-pacific/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/manta-pacific/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Manta RPC Method

# eth_getTransactionByHash - Manta RPC Method

Returns the information about a transaction by transaction hash on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getTransactionByHash` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Manta Pacific
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Manta Pacific. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Manta Pacific. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Manta RPC Method

# eth_getTransactionCount - Manta RPC Method

Returns the number of transactions sent from an address on Manta Pacific, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getTransactionCount` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Manta
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x0Dc808adcE2099A9F62AA87D9670745AbA741746', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Manta nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x0Dc808adcE2099A9F62AA87D9670745AbA741746'
nonce = get_transaction_count(address)
print(f'Manta nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Manta nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Manta:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x0Dc808adcE2099A9F62AA87D9670745AbA741746');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/manta-pacific/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Manta RPC Method

# eth_getTransactionReceipt - Manta RPC Method

Returns the receipt of a transaction by transaction hash on Manta Pacific. Receipt is only available for mined transactions.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_getTransactionReceipt` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Manta Pacific and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Manta Pacific. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Manta Pacific, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xf3134f27d41373e62496990ad048f81f01f3c7a86a431c99fa05dc20835f9cbd")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Manta RPC Method

# eth_hashrate - Manta RPC Method

Returns the legacy `eth_hashrate` compatibility value on Manta Pacific. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Manta hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Manta hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Manta hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Manta hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Manta hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/manta-pacific/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/manta-pacific/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Manta RPC Method

# eth_maxPriorityFeePerGas - Manta RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Manta Pacific. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Manta
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Manta priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Manta priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Manta priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Manta:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Manta:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/manta-pacific/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/manta-pacific/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Manta RPC Method

# eth_mining - Manta RPC Method

Checks the legacy `eth_mining` compatibility method on Manta Pacific. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Manta mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Manta mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Manta mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Manta mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Manta mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/manta-pacific/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/manta-pacific/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Manta RPC Method

# eth_newBlockFilter - Manta RPC Method

Creates a filter on Manta Pacific that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_newBlockFilter` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Block Monitoring** - Detect new blocks on Manta as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Manta:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/manta-pacific/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Manta RPC Method

# eth_newFilter - Manta RPC Method

Creates a filter object on Manta Pacific based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_newFilter` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Event Monitoring** - Subscribe to specific contract events on Manta such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x0Dc808adcE2099A9F62AA87D9670745AbA741746",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Manta:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/manta-pacific/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Manta RPC Method

# eth_newPendingTransactionFilter - Manta RPC Method

Creates a filter on Manta Pacific that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Mempool Monitoring** - Observe unconfirmed transactions on Manta to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for ZK-enabled DeFi, private identity verification, and modular ZK applications via Universal Circuits

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Manta...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Manta:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/manta-pacific/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Manta RPC Method

# eth_protocolVersion - Manta RPC Method

Returns the current Ethereum protocol version used by the Manta Pacific node.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_protocolVersion` is useful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Manta protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Manta protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Manta protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Manta protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Manta protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Manta nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/manta-pacific/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/manta-pacific/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/manta-pacific/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Manta RPC Method

# eth_sendRawTransaction - Manta RPC Method

Submits a pre-signed transaction for broadcast to Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Manta
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x0Dc808adcE2099A9F62AA87D9670745AbA741746', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Manta mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/manta-pacific/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x0Dc808adcE2099A9F62AA87D9670745AbA741746")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/manta-pacific/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Manta RPC Method

# eth_sendTransaction - Manta RPC Method

Creates and sends a new transaction from an unlocked account on Manta Pacific. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for ZK application developers, privacy-focused builders, and teams requiring modular scalability in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Manta tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Manta tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Manta tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Manta tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Manta tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Manta dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/manta-pacific/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Manta RPC Method

# eth_signTransaction - Manta RPC Method

Signs a transaction with the private key of the specified account on Manta Pacific without submitting it to the network.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for ZK application developers, privacy-focused builders, and teams requiring modular scalability in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Manta tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Manta tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Manta tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Manta:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/manta-pacific/eth_accounts) - List accounts available for signing

---

## eth_syncing - Manta RPC Method

# eth_syncing - Manta RPC Method

Returns the sync status of your Manta Pacific node - either `false` when fully synced, or an object describing the sync progress.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_syncing` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Manta node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Manta node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Manta node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/manta-pacific/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/manta-pacific/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/manta-pacific/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Manta RPC Method

# eth_uninstallFilter - Manta RPC Method

Removes a filter on Manta Pacific that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`eth_uninstallFilter` is important for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/manta-pacific/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/manta-pacific/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Manta RPC Method

# net_listening - Manta RPC Method

Checks whether the connected Manta Pacific client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`net_listening` is useful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Manta node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Manta node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Manta node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/manta-pacific/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/manta-pacific/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/manta-pacific/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/manta-pacific/web3_clientVersion) - Get node client info

---

## net_peerCount - Manta RPC Method

# net_peerCount - Manta RPC Method

Returns the number of peers currently connected to your Manta Pacific node.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`net_peerCount` is important for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Manta deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Manta peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Manta peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Manta peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Manta nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/manta-pacific/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/manta-pacific/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/manta-pacific/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/manta-pacific/web3_clientVersion) - Get node client info

---

## net_version - Manta RPC Method

# net_version - Manta RPC Method

Returns the current network ID on Manta Pacific as a decimal string. The network ID identifies which network the node is connected to.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`net_version` is essential for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Endpoint Identification** - Confirm your application is connected to the expected Manta network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Manta network ID:', networkId);

// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Manta network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Manta network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/manta-pacific/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/manta-pacific/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/manta-pacific/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/manta-pacific/eth_syncing) - Check node sync progress

---

## rpc_modules - Manta RPC Method

# rpc_modules - Manta RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Manta Pacific endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`rpc_modules` is useful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/manta-pacific/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/manta-pacific/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Manta RPC Method

# txpool_content - Manta RPC Method

Returns the full pending and queued transaction pool for the connected Manta Pacific endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`txpool_content` is useful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/manta-pacific/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/manta-pacific/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/manta-pacific/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Manta RPC Method

# txpool_status - Manta RPC Method

Returns transaction pool counters for the connected Manta Pacific endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`txpool_status` is valuable for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/manta-pacific/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/manta-pacific/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/manta-pacific/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Manta RPC Method

# web3_clientVersion - Manta RPC Method

Returns the current client software version string for your Manta Pacific node, including the client name, version number, OS, and runtime.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

## When to Use This Method

`web3_clientVersion` is valuable for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Manta client:', clientVersion);

// Using fetch
const response = await fetch('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Manta client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Manta client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/manta-pacific/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/manta-pacific/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/manta-pacific/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/manta-pacific/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Manta RPC Method

# web3_sha3 - Manta RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Manta Pacific.

> **Why Manta?** Build on the modular ZK L2 with Celestia DA delivering the lowest fees for 200+ dApps with first L2 on Celestia mainnet, ZK-as-a-Service via Universal Circuits, Polygon CDK integration, and modular OP Stack architecture.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for ZK application developers, privacy-focused builders, and teams requiring modular scalability:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-manta-pacific-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/manta-pacific/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/manta-pacific/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/manta-pacific/web3_clientVersion) - Get node client version

---

## Mantle - Modular L2 Documentation

# Mantle - Modular L2 Documentation

## Mantle RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Mantle supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Mantle?

Mantle Network is the first modular Layer 2 solution, pioneering the use of EigenDA for data availability. Built on the OP Stack with innovative architectural designs, Mantle offers:

### **Modular Performance**

- **Sub-second block times** - Fast finality with optimistic rollup
- **Up to 500x lower costs** than Ethereum mainnet
- **20,000+ TPS capacity** - High throughput for demanding applications

### **Advanced Security**

- **EigenDA integration** - First L2 with decentralized data availability
- **Optimistic rollup security** - Fraud proof protection with 7-day challenge period
- **Ethereum inheritance** - Full L1 security guarantees

### **Developer Excellence**

- **Full EVM compatibility** - Deploy existing contracts without changes
- **MNT gas token** - Native token for gas and governance
- **OP Stack foundation** - Battle-tested infrastructure

## Quick Start with Mantle

Connect to Mantle in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js
Web3.js
Python

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Mantle mainnet
const provider = new JsonRpcProvider(
  'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get network info
const network = await provider.getNetwork();
console.log('Connected to Mantle:', network.chainId); // 5000

// Query blockchain data
const blockNumber = await provider.getBlockNumber();
const balance = await provider.getBalance('0x...');
const gas = await provider.getFeeData();
```

```javascript
import Web3 from 'web3';

// Connect to Mantle
const web3 = new Web3(
  'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID
const chainId = await web3.eth.getChainId();
console.log('Chain ID:', chainId); // 5000n

// Query blockchain
const block = await web3.eth.getBlock('latest');
const balance = await web3.eth.getBalance('0x...');
const gasPrice = await web3.eth.getGasPrice();
```

```python
from web3 import Web3

# Connect to Mantle mainnet
w3 = Web3(Web3.HTTPProvider(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection
if w3.is_connected():
    print(f"Connected to Mantle")
    print(f"Chain ID: {w3.eth.chain_id}")  # 5000
    print(f"Latest block: {w3.eth.block_number}")

    # Get MNT balance
    address = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
    balance = w3.eth.get_balance(address)
    print(f"Balance: {w3.from_wei(balance, 'ether')} MNT")
```

## Network Information

### Mainnet Configuration

| Parameter      | Value                                          | Details |
| -------------- | ---------------------------------------------- | ------- |
| Network Name   | Mantle Network                                 |         |
| Chain ID       | `5000` (0x1388)                                |         |
| Currency       | MNT                                            |         |
| Block Explorer | [Mantle Explorer](https://explorer.mantle.xyz) |         |
| Bridge         | [Mantle Bridge](https://bridge.mantle.xyz)     |         |

### Testnet Configuration (Sepolia)

| Parameter      | Value                                                          | Details |
| -------------- | -------------------------------------------------------------- | ------- |
| Network Name   | Mantle Sepolia                                                 |         |
| Chain ID       | `5003` (0x138B)                                                |         |
| Currency       | MNT (Testnet)                                                  |         |
| Block Explorer | [Mantle Sepolia Explorer](https://explorer.testnet.mantle.xyz) |         |
| Faucet         | [Mantle Sepolia Faucet](https://faucet.testnet.mantle.xyz)     |         |

## Available RPC Methods

Mantle supports all standard Ethereum JSON-RPC methods plus L2-specific extensions:

### Core Methods

- **Transaction Management** - Send, sign, and track transactions
- **State Queries** - Get balances, code, storage
- **Block Information** - Query blocks and receipts
- **Event Logs** - Filter and retrieve events
- **Gas Estimation** - Estimate fees including L1 costs

### L2-Specific Methods

- `eth_estimateL1Fee` - Calculate L1 data posting costs
- `rollup_gasPrices` - Get current L1/L2 gas prices
- `rollup_getInfo` - Query rollup configuration

### Debug & Trace Methods

- `debug_traceTransaction` - Detailed transaction execution traces
- `debug_traceBlock` - Trace all transactions in a block
- `debug_traceCall` - Simulate and trace calls

## Architecture Overview

### Modular Design

Mantle's modular architecture separates core blockchain functions for optimal performance:

1. **Execution Layer** - Processes transactions using the EVM
2. **Settlement Layer** - Posts state commitments to Ethereum
3. **Data Availability Layer** - Uses EigenDA for efficient data storage
4. **Consensus Layer** - Inherits security from Ethereum L1

### EigenDA Integration

As the first L2 to integrate EigenDA, Mantle benefits from:

- **Lower costs** - Reduced data storage expenses
- **Higher throughput** - More efficient data availability
- **Decentralization** - Distributed DA layer
- **ETH restaking** - Additional security through EigenLayer

### Transaction Lifecycle

1. **Submission** - Users submit transactions to Mantle sequencer
2. **Execution** - Transactions processed in batches
3. **Data Posting** - Transaction data posted to EigenDA
4. **Settlement** - State root submitted to Ethereum L1
5. **Finality** - After 7-day challenge period

## Development Resources

### Smart Contract Deployment

Deploy your contracts to Mantle without modifications:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MantleApp {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
    }
}
```

### Using MNT Token

MNT is used for gas payments on Mantle:

```javascript
// Send MNT
const tx = await signer.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  value: ethers.parseEther('1.0') // 1 MNT
});

// Estimate gas in MNT
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getFeeData();
const gasCost = gasEstimate * gasPrice.gasPrice; // Cost in MNT
```

### Bridging Assets

Bridge assets between Ethereum and Mantle:

```javascript
// Bridge configuration
const BRIDGE_ADDRESS = '0x...'; // Mantle Bridge contract
const L1_TOKEN = '0x...'; // Token on Ethereum
const L2_TOKEN = '0x...'; // Token on Mantle

// Deposit from L1 to L2
async function depositToMantle(amount) {
  const bridge = new Contract(BRIDGE_ADDRESS, BRIDGE_ABI, l1Signer);
  const tx = await bridge.depositERC20(
    L1_TOKEN,
    L2_TOKEN,
    amount,
    { value: bridgeFee }
  );
  await tx.wait();
}
```

## Gas Optimization

### Understanding Mantle Fees

Mantle fees consist of two components:

1. **L2 Execution Fee** - Cost to run transaction on Mantle
2. **L1 Data Fee** - Cost to post data to Ethereum (via EigenDA)

```javascript
// Calculate total fee
const l2GasPrice = await provider.getGasPrice();
const l2GasUsed = await provider.estimateGas(tx);
const l1Fee = await provider.send('eth_estimateL1Fee', [tx]);

const totalFee = (l2GasPrice * l2GasUsed) + BigInt(l1Fee);
console.log('Total fee:', ethers.formatEther(totalFee), 'MNT');
```

### Optimization Tips

1. **Batch Operations** - Combine multiple operations in one transaction
2. **Use Events** - Cheaper than storage for data that doesn't need to be on-chain
3. **Optimize Calldata** - Minimize transaction input data
4. **Storage Packing** - Pack multiple values into single storage slots

## Common Use Cases

### DeFi Protocols

- Lower fees enable more frequent rebalancing and smaller trades
- High throughput supports order book DEXs
- Fast finality improves user experience

### Gaming & NFTs

- Affordable minting and trading
- High-frequency game actions
- Complex on-chain game logic

### DAOs & Governance

- Cost-effective voting
- More frequent proposal submissions
- On-chain treasury management

## Best Practices

### Error Handling

```javascript
try {
  const tx = await contract.someMethod();
  const receipt = await tx.wait();

  if (receipt.status === 0) {
    throw new Error('Transaction reverted');
  }
} catch (error) {
  if (error.code === 'CALL_EXCEPTION') {
    console.error('Contract reverted:', error.reason);
  } else if (error.code === 'INSUFFICIENT_FUNDS') {
    console.error('Not enough MNT for gas');
  }
}
```

### Rate Limiting

```javascript
// Implement exponential backoff
async function retryWithBackoff(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}
```

## Support & Resources

### Official Resources

- **Documentation**: [docs.mantle.xyz](https://docs.mantle.xyz)
- **GitHub**: [github.com/mantlenetworkio](https://github.com/mantlenetworkio)
- **Discord**: [discord.gg/mantle](https://discord.gg/mantle)
- **Twitter**: [@0xMantle](https://twitter.com/0xMantle)

### Dwellir Support

- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Status Page**: [status.dwellir.com](https://status.dwellir.com)
- **Support**: <support@dwellir.com>

## Start Building

Ready to build on Mantle? Get your free API key and start developing:

Launch Your Mantle dApp Today
Get instant access to Mantle's modular L2 with our high-performance RPC endpoints

Get Your Free API Key

***

*Need help? Check our [API reference](https://www.dwellir.com/docs/mantle/eth_blockNumber) or [contact support](mailto:support@dwellir.com).*

---

## debug_traceBlock - Mantle RPC Method

# debug_traceBlock - Mantle RPC Method

Traces all transactions in a block on Mantle by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Mantle - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Mantle
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Mantle:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Mantle blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/mantle/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/mantle/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/mantle/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/mantle/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Mantle RPC Method

# debug_traceBlockByHash - Mantle RPC Method

Traces all transactions in a block on Mantle identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Mantle - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Mantle
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Mantle:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Mantle:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/mantle/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/mantle/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/mantle/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/mantle/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/mantle/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Mantle RPC Method

# debug_traceBlockByNumber - Mantle RPC Method

Traces all transactions in a block on Mantle identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Mantle - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Mantle execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Mantle:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Mantle:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/mantle/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/mantle/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/mantle/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/mantle/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Mantle RPC Method

# debug_traceCall - Mantle RPC Method

Traces a call on Mantle without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Mantle - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Mantle
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "data": "0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
        "data": "0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
        "data": "0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    data: '0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    data: '0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    'data': '0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
        "data": "0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Mantle to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Mantle:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Mantle:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/mantle/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/mantle/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/mantle/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/mantle/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Mantle RPC Method

# debug_traceTransaction - Mantle RPC Method

Traces a transaction execution on Mantle by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Mantle
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/mantle/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/mantle/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Mantle RPC Method

# eth_accounts - Mantle RPC Method

Returns a list of addresses owned by the client on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/mantle/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/mantle/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Mantle RPC Method

# eth_blockNumber - Mantle RPC Method

Returns the number of the most recent block on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Syncing Applications** - Keep your dApp in sync with the latest Mantle blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Mantle block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Mantle block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Mantle block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Mantle block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Mantle block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Mantle:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Mantle:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Mantle node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/mantle/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/mantle/eth_syncing) - Check if node is still syncing

---

## eth_call - Mantle RPC Method

# eth_call - Mantle RPC Method

Executes a new message call immediately without creating a transaction on Mantle. Used for reading smart contract state.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Mantle
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';
const walletAddress = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Mantle. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Mantle
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Mantle

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "data": "0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "data": "0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    data := common.FromHex("0x70a0823100000000000000000000000078c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Mantle RPC Method

# eth_chainId - Mantle RPC Method

Returns the chain ID used for transaction signing on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/mantle/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/mantle/eth_syncing) - Check sync status

---

## eth_coinbase - Mantle RPC Method

# eth_coinbase - Mantle RPC Method

Checks the legacy `eth_coinbase` compatibility method on Mantle. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Mantle coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Mantle coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Mantle coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Mantle coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Mantle coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Mantle nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/mantle/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/mantle/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/mantle/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Mantle RPC Method

# eth_estimateGas - Mantle RPC Method

Estimates the gas necessary to execute a transaction on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Mantle
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Mantle.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Mantle may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "to": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 data posting fee

# eth_estimateL1Fee - Estimate L1 data posting fee

Estimate L1 data posting fee on the Mantle network. This method helps calculate the additional cost of posting transaction data to Ethereum L1 via EigenDA as part of Mantle's modular L2 architecture.

## Overview

Mantle's modular L2 is an optimistic rollup that periodically submits batched transaction data to Ethereum L1 through EigenDA for data availability. While most transaction execution happens on L2 with low gas costs paid in MNT, there's an additional fee component for the L1 data availability costs.

## Request Parameters

- `transaction` (`Object, required`): Transaction object to estimate L1 fee for

## Request Example

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \\
      -H "Content-Type: application/json" \\
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [
          {
            "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5",
            "to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "gas": "0x5208",
            "gasPrice": "0x3b9aca00",
            "value": "0x1bc16d674ec80000",
            "data": "0x"
          }
        ],
        "id": 1
      }'
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated L1 fee in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c6bf526340"
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \\
  -H "Content-Type: application/json" \\
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateL1Fee",
    "params": [
      {
        "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5",
        "to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "gas": "0x5208",
        "gasPrice": "0x3b9aca00",
        "value": "0x1bc16d674ec80000",
        "data": "0x"
      }
    ],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_estimateL1Fee',
    params: [
      {
        from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
        to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
        gas: '0x5208',
        gasPrice: '0x3b9aca00',
        value: '0x1bc16d674ec80000',
        data: '0x'
      }
    ],
    id: 1
  })
});

const data = await response.json();
console.log('L1 Fee:', data.result);

// Advanced L1 fee estimation with transaction cost breakdown
class MantleFeeEstimator {
  constructor(rpcUrl) {
    this.rpcUrl = rpcUrl;
  }

  async estimateL1Fee(transaction) {
    const response = await fetch(this.rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'eth_estimateL1Fee',
        params: [transaction],
        id: 1
      })
    });

    const data = await response.json();
    
    if (data.error) {
      throw new Error(`RPC Error: ${data.error.message}`);
    }

    return parseInt(data.result, 16);
  }

  async getFullFeeBreakdown(transaction) {
    try {
      // Estimate L2 gas cost
      const l2GasResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_estimateGas',
          params: [transaction],
          id: 1
        })
      });

      const l2GasData = await l2GasResponse.json();
      const l2GasEstimate = parseInt(l2GasData.result, 16);

      // Get current gas price
      const gasPriceResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_gasPrice',
          params: [],
          id: 1
        })
      });

      const gasPriceData = await gasPriceResponse.json();
      const gasPrice = parseInt(gasPriceData.result, 16);

      // Estimate L1 fee
      const l1Fee = await this.estimateL1Fee(transaction);

      // Calculate L2 execution cost (paid in MNT)
      const l2ExecutionCost = l2GasEstimate * gasPrice;

      return {
        l1Fee: l1Fee,
        l2ExecutionCost: l2ExecutionCost,
        totalEstimatedCost: l1Fee + l2ExecutionCost,
        gasEstimate: l2GasEstimate,
        gasPrice: gasPrice,
        breakdown: {
          l1FeePercentage: ((l1Fee / (l1Fee + l2ExecutionCost)) * 100).toFixed(2),
          l2FeePercentage: ((l2ExecutionCost / (l1Fee + l2ExecutionCost)) * 100).toFixed(2)
        }
      };
    } catch (error) {
      throw new Error(`Failed to get fee breakdown: ${error.message}`);
    }
  }

  async compareFeesByDataSize(baseTransaction, dataSizes) {
    const results = [];

    for (const size of dataSizes) {
      // Generate test data of specified size
      const testData = '0x' + '00'.repeat(size);
      
      const testTransaction = {
        ...baseTransaction,
        data: testData
      };

      try {
        const breakdown = await this.getFullFeeBreakdown(testTransaction);
        
        results.push({
          dataSize: size,
          dataSizeKB: (size / 1024).toFixed(2),
          l1Fee: breakdown.l1Fee,
          l2ExecutionCost: breakdown.l2ExecutionCost,
          totalCost: breakdown.totalEstimatedCost,
          l1FeePerByte: breakdown.l1Fee / size,
          costIncrease: size === dataSizes[0] ? 0 : 
            ((breakdown.totalEstimatedCost - results[0].totalCost) / results[0].totalCost * 100).toFixed(2)
        });
      } catch (error) {
        results.push({
          dataSize: size,
          error: error.message
        });
      }
    }

    return results;
  }

  async optimizeTransactionCost(transaction) {
    const recommendations = [];
    
    // Get baseline cost
    const baseline = await this.getFullFeeBreakdown(transaction);
    
    // Check if transaction has unnecessary data
    if (transaction.data && transaction.data.length > 2) {
      // Estimate with minimal data
      const minimalTx = { ...transaction, data: '0x' };
      const minimal = await this.getFullFeeBreakdown(minimalTx);
      
      const dataCostSavings = baseline.l1Fee - minimal.l1Fee;
      
      if (dataCostSavings > 0) {
        recommendations.push({
          type: 'data_optimization',
          description: 'Consider reducing transaction data size',
          potentialSavings: dataCostSavings,
          savingsPercentage: ((dataCostSavings / baseline.totalEstimatedCost) * 100).toFixed(2)
        });
      }
    }

    // Check gas optimization
    if (baseline.gasEstimate > 100000) {
      recommendations.push({
        type: 'gas_optimization',
        description: 'High gas usage detected - consider optimizing contract calls',
        currentGas: baseline.gasEstimate,
        suggestion: 'Review contract logic for gas efficiency'
      });
    }

    // Check if L1 fees dominate
    if (parseFloat(baseline.breakdown.l1FeePercentage) > 70) {
      recommendations.push({
        type: 'l1_fee_dominance',
        description: 'L1 fees represent majority of transaction cost',
        l1Percentage: baseline.breakdown.l1FeePercentage,
        suggestion: 'Consider batching transactions or reducing data payload'
      });
    }

    return {
      baseline: baseline,
      recommendations: recommendations,
      optimizationPotential: recommendations.length > 0
    };
  }
}

// Usage examples
const feeEstimator = new MantleFeeEstimator('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Basic L1 fee estimation
const l1Fee = await feeEstimator.estimateL1Fee({
  from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
  to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  value: '0x1bc16d674ec80000',
  data: '0x'
});

console.log(`L1 Fee: ${l1Fee} wei`);

// Full fee breakdown
const breakdown = await feeEstimator.getFullFeeBreakdown({
  from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
  to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  value: '0x1bc16d674ec80000',
  data: '0xa9059cbb000000000000000000000000recipient000000000000000000000000'
});

console.log('Fee Breakdown:', breakdown);

// Compare fees by data size
const dataSizeComparison = await feeEstimator.compareFeesByDataSize(
  {
    from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
    to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
  },
  [0, 100, 500, 1000, 5000] // bytes
);

console.log('Data Size Impact:', dataSizeComparison);

// Optimization suggestions
const optimization = await feeEstimator.optimizeTransactionCost({
  from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
  to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
  data: '0xa9059cbb' + '0'.repeat(1000) // Large data payload
});

console.log('Optimization Analysis:', optimization);
```

```python
import requests
import json
from typing import Dict, List, Any, Optional

class MantleFeeEstimator:
    """Estimate L1 fees and analyze transaction costs on Mantle modular L2"""
    
    def __init__(self, rpc_url: str):
        self.rpc_url = rpc_url
    
    def estimate_l1_fee(self, transaction: Dict[str, Any]) -> int:
        """Estimate L1 data posting fee for a transaction"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_estimateL1Fee",
            "params": [transaction],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return int(data['result'], 16)
    
    def _make_rpc_call(self, method: str, params: List = None) -> Any:
        """Helper method for RPC calls"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params or [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def get_full_fee_breakdown(self, transaction: Dict[str, Any]) -> Dict[str, Any]:
        """Get complete fee breakdown including L1 and L2 costs"""
        
        # Estimate L2 gas
        l2_gas_estimate = int(self._make_rpc_call('eth_estimateGas', [transaction]), 16)
        
        # Get current gas price
        gas_price = int(self._make_rpc_call('eth_gasPrice'), 16)
        
        # Estimate L1 fee
        l1_fee = self.estimate_l1_fee(transaction)
        
        # Calculate L2 execution cost (paid in MNT)
        l2_execution_cost = l2_gas_estimate * gas_price
        
        total_cost = l1_fee + l2_execution_cost
        
        return {
            'l1_fee': l1_fee,
            'l2_execution_cost': l2_execution_cost,
            'total_estimated_cost': total_cost,
            'gas_estimate': l2_gas_estimate,
            'gas_price': gas_price,
            'breakdown': {
                'l1_fee_percentage': round((l1_fee / total_cost) * 100, 2) if total_cost > 0 else 0,
                'l2_fee_percentage': round((l2_execution_cost / total_cost) * 100, 2) if total_cost > 0 else 0
            }
        }
    
    def analyze_data_cost_impact(
        self,
        base_transaction: Dict[str, Any],
        data_payloads: List[str]
    ) -> List[Dict[str, Any]]:
        """Analyze how different data payloads affect L1 fees"""
        
        results = []
        
        for i, data in enumerate(data_payloads):
            test_tx = {**base_transaction, 'data': data}
            
            try:
                breakdown = self.get_full_fee_breakdown(test_tx)
                data_size = (len(data) - 2) // 2 if data.startswith('0x') else len(data) // 2
                
                result = {
                    'data_payload': data[:20] + '...' if len(data) > 20 else data,
                    'data_size_bytes': data_size,
                    'l1_fee': breakdown['l1_fee'],
                    'l2_execution_cost': breakdown['l2_execution_cost'],
                    'total_cost': breakdown['total_estimated_cost'],
                    'l1_fee_per_byte': breakdown['l1_fee'] / data_size if data_size > 0 else 0
                }
                
                # Calculate cost increase relative to first payload
                if i > 0 and results:
                    base_cost = results[0]['total_cost']
                    result['cost_increase_pct'] = round(
                        ((result['total_cost'] - base_cost) / base_cost) * 100, 2
                    ) if base_cost > 0 else 0
                else:
                    result['cost_increase_pct'] = 0
                
                results.append(result)
                
            except Exception as e:
                results.append({
                    'data_payload': data[:20] + '...' if len(data) > 20 else data,
                    'error': str(e)
                })
        
        return results
    
    def suggest_optimizations(self, transaction: Dict[str, Any]) -> Dict[str, Any]:
        """Analyze transaction and suggest cost optimizations"""
        
        baseline = self.get_full_fee_breakdown(transaction)
        suggestions = []
        
        # Check data optimization potential
        if transaction.get('data') and len(transaction['data']) > 2:
            minimal_tx = {**transaction, 'data': '0x'}
            minimal_cost = self.get_full_fee_breakdown(minimal_tx)
            
            data_cost_impact = baseline['l1_fee'] - minimal_cost['l1_fee']
            
            if data_cost_impact > 0:
                suggestions.append({
                    'type': 'data_optimization',
                    'description': 'Transaction data contributes significantly to L1 costs',
                    'potential_savings_wei': data_cost_impact,
                    'potential_savings_pct': round(
                        (data_cost_impact / baseline['total_estimated_cost']) * 100, 2
                    ),
                    'recommendation': 'Consider compressing data or using events for large payloads'
                })
        
        # Check gas efficiency
        if baseline['gas_estimate'] > 200000:
            suggestions.append({
                'type': 'gas_optimization',
                'description': f'High gas usage detected: {baseline["gas_estimate"]:,} gas',
                'recommendation': 'Review contract logic for gas efficiency improvements'
            })
        
        # Check fee composition
        if baseline['breakdown']['l1_fee_percentage'] > 80:
            suggestions.append({
                'type': 'l1_fee_dominance',
                'description': f'L1 fees dominate total cost ({baseline["breakdown"]["l1_fee_percentage"]}%)',
                'recommendation': 'Consider batching multiple operations into single transaction'
            })
        
        return {
            'baseline_cost': baseline,
            'optimization_suggestions': suggestions,
            'total_potential_savings': sum(
                s.get('potential_savings_wei', 0) for s in suggestions
            )
        }
    
    def compare_transaction_efficiency(
        self,
        transactions: List[Dict[str, Any]],
        labels: List[str] = None
    ) -> Dict[str, Any]:
        """Compare efficiency of different transaction approaches"""
        
        if labels is None:
            labels = [f"Transaction {i+1}" for i in range(len(transactions))]
        
        comparisons = []
        
        for i, (tx, label) in enumerate(zip(transactions, labels)):
            try:
                breakdown = self.get_full_fee_breakdown(tx)
                
                comparisons.append({
                    'label': label,
                    'total_cost': breakdown['total_estimated_cost'],
                    'l1_fee': breakdown['l1_fee'],
                    'l2_cost': breakdown['l2_execution_cost'],
                    'gas_estimate': breakdown['gas_estimate'],
                    'efficiency_score': breakdown['gas_estimate'] / breakdown['total_estimated_cost']
                })
            except Exception as e:
                comparisons.append({
                    'label': label,
                    'error': str(e)
                })
        
        # Find most efficient
        valid_comparisons = [c for c in comparisons if 'error' not in c]
        
        if valid_comparisons:
            most_efficient = min(valid_comparisons, key=lambda x: x['total_cost'])
            least_efficient = max(valid_comparisons, key=lambda x: x['total_cost'])
            
            return {
                'comparisons': comparisons,
                'most_efficient': most_efficient,
                'least_efficient': least_efficient,
                'cost_difference': least_efficient['total_cost'] - most_efficient['total_cost'],
                'efficiency_improvement_pct': round(
                    ((least_efficient['total_cost'] - most_efficient['total_cost']) /
                     least_efficient['total_cost']) * 100, 2
                )
            }
        
        return {'comparisons': comparisons}

# Usage examples
fee_estimator = MantleFeeEstimator('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY')

# Basic L1 fee estimation
transaction = {
    'from': '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
    'to': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
    'value': '0x1bc16d674ec80000',
    'data': '0xa9059cbb000000000000000000000000recipient000000000000000000000000'
}

l1_fee = fee_estimator.estimate_l1_fee(transaction)
print(f"L1 Fee: {l1_fee:,} wei")

# Full breakdown
breakdown = fee_estimator.get_full_fee_breakdown(transaction)
print(f"Total Cost: {breakdown['total_estimated_cost']:,} wei")
print(f"L1 Fee: {breakdown['l1_fee']:,} wei ({breakdown['breakdown']['l1_fee_percentage']}%)")
print(f"L2 Cost: {breakdown['l2_execution_cost']:,} wei ({breakdown['breakdown']['l2_fee_percentage']}%)")

# Data impact analysis
data_payloads = [
    '0x',  # Empty
    '0xa9059cbb' + '00' * 32,  # Basic ERC20 transfer
    '0xa9059cbb' + '00' * 100,  # Larger payload
    '0xa9059cbb' + '00' * 500   # Very large payload
]

data_analysis = fee_estimator.analyze_data_cost_impact(
    {'from': '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5', 'to': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'},
    data_payloads
)

print("\nData Size Impact Analysis:")
for result in data_analysis:
    if 'error' not in result:
        print(f"  {result['data_size_bytes']} bytes: {result['total_cost']:,} wei "
              f"(+{result['cost_increase_pct']}%)")

# Optimization suggestions
optimization = fee_estimator.suggest_optimizations(transaction)
print(f"\nOptimization Suggestions:")
for suggestion in optimization['optimization_suggestions']:
    print(f"  - {suggestion['description']}")
    print(f"    {suggestion['recommendation']}")
```

## Understanding L1 Fees on Mantle

### Fee Components

1. **L2 Execution Fee**: Standard gas cost for transaction execution on Mantle (paid in MNT)
2. **L1 Data Fee**: Cost of posting transaction data to Ethereum L1 via EigenDA for data availability

### Data Size Impact

L1 fees scale with transaction data size:

- Simple transfers: Minimal L1 fee
- Contract interactions: Moderate L1 fee based on calldata
- Large data payloads: Significant L1 fee component

### Cost Optimization Strategies

1. **Minimize Data**: Reduce unnecessary data in transactions
2. **Batch Operations**: Combine multiple operations into single transaction
3. **Use Events**: Emit events instead of storing large data on-chain
4. **Optimize Encoding**: Use efficient data encoding methods
5. **Leverage EigenDA**: Benefit from efficient data availability

## Common Use Cases

### 1. Transaction Cost Planning

```javascript
// Plan transaction costs before execution
async function planTransactionCosts(transactions) {
  const feeEstimator = new MantleFeeEstimator(rpcUrl);
  const plans = [];
  
  for (const tx of transactions) {
    const breakdown = await feeEstimator.getFullFeeBreakdown(tx);
    plans.push({
      transaction: tx,
      estimatedCost: breakdown.totalEstimatedCost,
      l1FeeRatio: breakdown.breakdown.l1FeePercentage,
      recommendation: breakdown.breakdown.l1FeePercentage > 70 ? 
        'Consider batching or data optimization' : 'Cost efficient'
    });
  }
  
  return plans.sort((a, b) => a.estimatedCost - b.estimatedCost);
}
```

### 2. Data Optimization Analysis

```python
def optimize_contract_call_data(base_transaction, data_variations):
    """Find most cost-effective data encoding"""
    
    fee_estimator = MantleFeeEstimator(rpc_url)
    results = []
    
    for name, data in data_variations.items():
        tx = {**base_transaction, 'data': data}
        breakdown = fee_estimator.get_full_fee_breakdown(tx)
        
        results.append({
            'encoding': name,
            'data_size': len(data) // 2 - 1,  # Hex bytes
            'total_cost': breakdown['total_estimated_cost'],
            'l1_fee': breakdown['l1_fee'],
            'efficiency': breakdown['l1_fee'] / (len(data) // 2 - 1)
        })
    
    # Sort by total cost
    return sorted(results, key=lambda x: x['total_cost'])
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate L2 execution gas
- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Get current L2 gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/mantle/eth_feeHistory) - Historical fee data

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Mantle documentation](https://www.dwellir.com/docs/mantle).*

---

## eth_feeHistory - Mantle RPC Method

# eth_feeHistory - Mantle RPC Method

Returns historical gas fee data on Mantle, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Mantle without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Mantle.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Mantle) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/mantle/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Mantle RPC Method

# eth_gasPrice - Mantle RPC Method

Returns the current gas price on Mantle in wei.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Mantle
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Mantle. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Mantle, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Mantle: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Mantle supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/mantle/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/mantle/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Mantle RPC Method

# eth_getBalance - Mantle RPC Method

Returns the balance of a given address on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Mantle
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Mantle
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Mantle. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Mantle`);
  return balance;
}

displayBalance('0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Mantle at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Mantle')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Mantle')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Mantle.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/mantle/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/mantle/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Mantle RPC Method

# eth_getBlockByHash - Mantle RPC Method

Returns information about a block by hash on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Mantle
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Mantle.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Mantle.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Mantle RPC Method

# eth_getBlockByNumber - Mantle RPC Method

Returns information about a block by block number on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Mantle
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Mantle with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Mantle. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/mantle/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/mantle/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Mantle RPC Method

# eth_getBlockReceipts - Mantle RPC Method

Returns all transaction receipts for a block on Mantle. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Mantle, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Mantle. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x731df9ec5eb8000dc29641dfbebb0efef7660fff0b55f64e402eec934af2c538",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/mantle/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/mantle/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Mantle RPC Method

# eth_getCode - Mantle RPC Method

Returns the bytecode at a given address on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Mantle
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Mantle:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Mantle:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/mantle/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/mantle/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Mantle RPC Method

# eth_getFilterChanges - Mantle RPC Method

Polls a filter on Mantle for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Mantle
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Mantle:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/mantle/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/mantle/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/mantle/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/mantle/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/mantle/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Mantle RPC Method

# eth_getFilterLogs - Mantle RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Mantle. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Mantle
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/mantle/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/mantle/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/mantle/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/mantle/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Mantle RPC Method

# eth_getLogs - Mantle RPC Method

Returns an array of all logs matching a given filter object on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Mantle for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Mantle
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Mantle.

```javascript
const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Mantle enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Mantle, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/mantle/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/mantle/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Mantle RPC Method

# eth_getStorageAt - Mantle RPC Method

Returns the value from a storage position at a given address on Mantle. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **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 liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **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": [
    "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "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-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', '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-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';

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-mantle-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 = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
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-mantle-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-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    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 Mantle:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-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-mantle-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 = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';
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 Mantle:`);
  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/mantle/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/mantle/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/mantle/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Mantle RPC Method

# eth_getTransactionByHash - Mantle RPC Method

Returns the information about a transaction by transaction hash on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Mantle
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Mantle. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Mantle. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/mantle/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Mantle RPC Method

# eth_getTransactionCount - Mantle RPC Method

Returns the number of transactions sent from an address on Mantle, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Mantle
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Mantle nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8'
nonce = get_transaction_count(address)
print(f'Mantle nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Mantle nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Mantle:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/mantle/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/mantle/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/mantle/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Mantle RPC Method

# eth_getTransactionReceipt - Mantle RPC Method

Returns the receipt of a transaction by transaction hash on Mantle. Receipt is only available for mined transactions.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Mantle and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Mantle. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Mantle, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x01fec3bc45d186d1bffc3ed7e7fd88bd8408f5b4c68a86a83c54c60846589b06")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/mantle/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/mantle/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Mantle RPC Method

# eth_hashrate - Mantle RPC Method

Returns the legacy `eth_hashrate` compatibility value on Mantle. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Mantle hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Mantle hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Mantle hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Mantle hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Mantle hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/mantle/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/mantle/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Mantle RPC Method

# eth_maxPriorityFeePerGas - Mantle RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Mantle. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Mantle
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Mantle priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Mantle priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Mantle priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Mantle:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Mantle:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/mantle/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Mantle RPC Method

# eth_mining - Mantle RPC Method

Checks the legacy `eth_mining` compatibility method on Mantle. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Mantle mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Mantle mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Mantle mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Mantle mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Mantle mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/mantle/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/mantle/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Mantle RPC Method

# eth_newBlockFilter - Mantle RPC Method

Creates a filter on Mantle that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Block Monitoring** - Detect new blocks on Mantle as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Mantle:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/mantle/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/mantle/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/mantle/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Mantle RPC Method

# eth_newFilter - Mantle RPC Method

Creates a filter object on Mantle based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Event Monitoring** - Subscribe to specific contract events on Mantle such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Mantle:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/mantle/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/mantle/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/mantle/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/mantle/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/mantle/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Mantle RPC Method

# eth_newPendingTransactionFilter - Mantle RPC Method

Creates a filter on Mantle that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Mempool Monitoring** - Observe unconfirmed transactions on Mantle to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for liquid staking (mETH $1.87B TVL), institutional DeFi via Bybit, and yield optimization strategies

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Mantle...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Mantle:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/mantle/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/mantle/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/mantle/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Mantle RPC Method

# eth_protocolVersion - Mantle RPC Method

Returns the current Ethereum protocol version used by the Mantle node.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Mantle protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Mantle protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Mantle protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Mantle protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Mantle protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Mantle nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/mantle/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/mantle/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/mantle/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Mantle RPC Method

# eth_sendRawTransaction - Mantle RPC Method

Submits a pre-signed transaction for broadcast to Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Mantle
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Mantle mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/mantle/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/mantle/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Mantle RPC Method

# eth_sendTransaction - Mantle RPC Method

Creates and sends a new transaction from an unlocked account on Mantle. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Mantle tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Mantle tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Mantle tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Mantle tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Mantle tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Mantle dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/mantle/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Mantle RPC Method

# eth_signTransaction - Mantle RPC Method

Signs a transaction with the private key of the specified account on Mantle without submitting it to the network.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Mantle tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Mantle tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Mantle tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Mantle:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/mantle/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/mantle/eth_accounts) - List accounts available for signing

---

## eth_syncing - Mantle RPC Method

# eth_syncing - Mantle RPC Method

Returns the sync status of your Mantle node - either `false` when fully synced, or an object describing the sync progress.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Mantle node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Mantle node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Mantle node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/mantle/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/mantle/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/mantle/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Mantle RPC Method

# eth_uninstallFilter - Mantle RPC Method

Removes a filter on Mantle that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/mantle/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/mantle/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/mantle/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/mantle/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/mantle/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Mantle RPC Method

# net_listening - Mantle RPC Method

Checks whether the connected Mantle client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`net_listening` is useful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Mantle node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Mantle node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Mantle node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/mantle/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/mantle/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/mantle/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/mantle/web3_clientVersion) - Get node client info

---

## net_peerCount - Mantle RPC Method

# net_peerCount - Mantle RPC Method

Returns the number of peers currently connected to your Mantle node.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`net_peerCount` is important for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Mantle deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Mantle peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Mantle peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Mantle peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Mantle nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/mantle/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/mantle/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/mantle/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/mantle/web3_clientVersion) - Get node client info

---

## net_version - Mantle RPC Method

# net_version - Mantle RPC Method

Returns the current network ID on Mantle as a decimal string. The network ID identifies which network the node is connected to.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`net_version` is essential for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Endpoint Identification** - Confirm your application is connected to the expected Mantle network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Mantle network ID:', networkId);

// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Mantle network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Mantle network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/mantle/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/mantle/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/mantle/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/mantle/eth_syncing) - Check node sync progress

---

## rollup_gasPrices - Get modular L2 gas price o...

# rollup_gasPrices - Get modular L2 gas price o...

Get modular L2 gas price oracle data on the Mantle network. This method provides comprehensive gas pricing information for the optimistic rollup, including both L2 execution costs and L1 data availability fees.

## Overview

Mantle's modular L2 architecture uses a sophisticated gas pricing mechanism that accounts for:

- **L2 Execution Costs**: Gas costs for transaction execution on the optimistic rollup
- **L1 Data Availability**: Costs for posting transaction data to Ethereum L1 via EigenDA
- **Sequencer Operations**: Costs associated with transaction ordering and batch processing

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \\
      -H "Content-Type: application/json" \\
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Gas price oracle data object containing current pricing information for the modular L2 rollup.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "l1GasPrice": "0x12a05f200",
    "l2GasPrice": "0x3b9aca00",
    "overhead": "0xbc0",
    "scalar": "0x684000",
    "decimals": "0x6"
  }
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \\
  -H "Content-Type: application/json" \\
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_gasPrices",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_gasPrices',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Gas Prices:', data.result);

// Advanced gas price monitoring for Mantle modular L2
class MantleGasPriceMonitor {
  constructor(rpcUrl) {
    this.rpcUrl = rpcUrl;
    this.priceHistory = [];
  }

  async getGasPrices() {
    const response = await fetch(this.rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'rollup_gasPrices',
        params: [],
        id: 1
      })
    });

    const data = await response.json();
    
    if (data.error) {
      throw new Error(`RPC Error: ${data.error.message}`);
    }

    return data.result;
  }

  async getCurrentPricing() {
    try {
      // Get rollup gas prices
      const rollupPrices = await this.getGasPrices();
      
      // Get standard gas price for comparison
      const standardGasResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_gasPrice',
          params: [],
          id: 1
        })
      });

      const standardGasData = await standardGasResponse.json();
      const standardGasPrice = parseInt(standardGasData.result, 16);

      return {
        timestamp: Date.now(),
        rollupPrices: rollupPrices,
        standardGasPrice: standardGasPrice,
        formattedPrices: this.formatPrices(rollupPrices, standardGasPrice)
      };
    } catch (error) {
      throw new Error(`Failed to get pricing: ${error.message}`);
    }
  }

  formatPrices(rollupPrices, standardGasPrice) {
    return {
      standardGasPrice: {
        wei: standardGasPrice,
        gwei: (standardGasPrice / 1e9).toFixed(2),
        mnt: (standardGasPrice / 1e18).toFixed(8)
      },
      rollupData: rollupPrices // This will depend on actual response format
    };
  }

  async trackPriceHistory(duration = 3600000, interval = 60000) {
    // Track gas prices for specified duration (default 1 hour) at intervals (default 1 minute)
    const startTime = Date.now();
    const endTime = startTime + duration;

    console.log(`Starting price tracking for ${duration / 60000} minutes...`);

    while (Date.now() < endTime) {
      try {
        const pricing = await this.getCurrentPricing();
        this.priceHistory.push(pricing);
        
        console.log(`Price update: ${pricing.formattedPrices.standardGasPrice.gwei} gwei`);
        
        await new Promise(resolve => setTimeout(resolve, interval));
      } catch (error) {
        console.error('Price tracking error:', error.message);
        await new Promise(resolve => setTimeout(resolve, interval));
      }
    }

    return this.analyzePriceHistory();
  }

  analyzePriceHistory() {
    if (this.priceHistory.length === 0) {
      return { error: 'No price history available' };
    }

    const prices = this.priceHistory.map(p => p.standardGasPrice);
    const sortedPrices = [...prices].sort((a, b) => a - b);

    const analysis = {
      duration: {
        start: new Date(this.priceHistory[0].timestamp).toISOString(),
        end: new Date(this.priceHistory[this.priceHistory.length - 1].timestamp).toISOString(),
        dataPoints: this.priceHistory.length
      },
      statistics: {
        min: Math.min(...prices),
        max: Math.max(...prices),
        average: prices.reduce((sum, p) => sum + p, 0) / prices.length,
        median: sortedPrices[Math.floor(sortedPrices.length / 2)],
        volatility: this.calculateVolatility(prices)
      },
      trends: {
        direction: this.getTrend(prices),
        priceChange: prices[prices.length - 1] - prices[0],
        percentageChange: ((prices[prices.length - 1] - prices[0]) / prices[0] * 100).toFixed(2)
      },
      recommendations: this.generateRecommendations(prices)
    };

    return analysis;
  }

  calculateVolatility(prices) {
    if (prices.length < 2) return 0;
    
    const mean = prices.reduce((sum, p) => sum + p, 0) / prices.length;
    const variance = prices.reduce((sum, p) => sum + Math.pow(p - mean, 2), 0) / prices.length;
    return Math.sqrt(variance);
  }

  getTrend(prices) {
    if (prices.length < 2) return 'insufficient_data';
    
    const firstHalf = prices.slice(0, Math.floor(prices.length / 2));
    const secondHalf = prices.slice(Math.floor(prices.length / 2));
    
    const firstAvg = firstHalf.reduce((sum, p) => sum + p, 0) / firstHalf.length;
    const secondAvg = secondHalf.reduce((sum, p) => sum + p, 0) / secondHalf.length;
    
    const changePct = ((secondAvg - firstAvg) / firstAvg) * 100;
    
    if (changePct > 5) return 'increasing';
    if (changePct < -5) return 'decreasing';
    return 'stable';
  }

  generateRecommendations(prices) {
    const recommendations = [];
    const currentPrice = prices[prices.length - 1];
    const avgPrice = prices.reduce((sum, p) => sum + p, 0) / prices.length;
    const minPrice = Math.min(...prices);
    
    if (currentPrice > avgPrice * 1.2) {
      recommendations.push({
        type: 'high_gas_warning',
        message: 'Current gas price is significantly above average',
        suggestion: 'Consider waiting for lower gas prices or using lower priority'
      });
    }
    
    if (currentPrice <= minPrice * 1.1) {
      recommendations.push({
        type: 'optimal_timing',
        message: 'Current gas price is near historical low',
        suggestion: 'Good time to execute transactions'
      });
    }
    
    const volatility = this.calculateVolatility(prices);
    if (volatility > avgPrice * 0.1) {
      recommendations.push({
        type: 'high_volatility',
        message: 'Gas prices are highly volatile',
        suggestion: 'Monitor prices closely and be prepared to adjust'
      });
    }
    
    return recommendations;
  }

  async predictOptimalTiming(targetGasPrice) {
    const pricing = await this.getCurrentPricing();
    const currentPrice = pricing.standardGasPrice;
    
    if (currentPrice <= targetGasPrice) {
      return {
        optimal: true,
        currentPrice: currentPrice,
        targetPrice: targetGasPrice,
        recommendation: 'Execute transaction now'
      };
    }
    
    // Simple prediction based on recent trend
    const recentPrices = this.priceHistory.slice(-10).map(p => p.standardGasPrice);
    const trend = this.getTrend(recentPrices);
    
    let prediction = 'unknown';
    let estimatedWait = 'unknown';
    
    if (trend === 'decreasing') {
      prediction = 'prices_likely_to_drop';
      estimatedWait = 'monitor_for_15_30_minutes';
    } else if (trend === 'increasing') {
      prediction = 'prices_likely_to_rise';
      estimatedWait = 'consider_executing_soon';
    } else {
      prediction = 'prices_stable';
      estimatedWait = 'no_clear_trend';
    }
    
    return {
      optimal: false,
      currentPrice: currentPrice,
      targetPrice: targetGasPrice,
      prediction: prediction,
      estimatedWait: estimatedWait,
      recommendation: `Current: ${(currentPrice / 1e9).toFixed(2)} gwei, Target: ${(targetGasPrice / 1e9).toFixed(2)} gwei`
    };
  }

  async compareWithL1Costs() {
    try {
      // Get Mantle gas prices
      const mantlePricing = await this.getCurrentPricing();
      
      // For comparison with Ethereum L1, you would need to call Ethereum mainnet
      // This is just an example structure
      const comparison = {
        mantle: {
          gasPrice: mantlePricing.standardGasPrice,
          gasPriceGwei: mantlePricing.formattedPrices.standardGasPrice.gwei,
          estimatedTransferCost: mantlePricing.standardGasPrice * 21000 // MNT transfer
        },
        savings: {
          // This would be calculated with actual L1 data
          estimatedSavings: 'Requires L1 comparison data',
          savingsPercentage: 'Requires L1 comparison data'
        }
      };
      
      return comparison;
    } catch (error) {
      throw new Error(`Failed to compare costs: ${error.message}`);
    }
  }
}

// Usage examples
const gasPriceMonitor = new MantleGasPriceMonitor('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get current gas pricing
const currentPricing = await gasPriceMonitor.getCurrentPricing();
console.log('Current Gas Prices:', currentPricing.formattedPrices);

// Track prices for 10 minutes
const priceAnalysis = await gasPriceMonitor.trackPriceHistory(600000, 30000);
console.log('Price Analysis:', priceAnalysis);

// Check optimal timing for transaction
const optimalTiming = await gasPriceMonitor.predictOptimalTiming(20000000000); // 20 gwei target
console.log('Optimal Timing:', optimalTiming);

// Compare with L1 costs
const costComparison = await gasPriceMonitor.compareWithL1Costs();
console.log('Cost Comparison:', costComparison);
```

```python
import requests
import json
import time
import statistics
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta

class MantleGasPriceAnalyzer:
    """Analyze and monitor gas prices on Mantle modular L2"""
    
    def __init__(self, rpc_url: str):
        self.rpc_url = rpc_url
        self.price_history = []
    
    def get_rollup_gas_prices(self) -> Dict[str, Any]:
        """Get current rollup gas prices"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "rollup_gasPrices",
            "params": [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def get_standard_gas_price(self) -> int:
        """Get standard gas price for comparison"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "eth_gasPrice",
            "params": [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return int(data['result'], 16)
    
    def get_comprehensive_pricing(self) -> Dict[str, Any]:
        """Get comprehensive gas pricing information"""
        
        rollup_prices = self.get_rollup_gas_prices()
        standard_gas_price = self.get_standard_gas_price()
        
        return {
            'timestamp': datetime.now().isoformat(),
            'rollup_data': rollup_prices,
            'standard_gas_price': standard_gas_price,
            'formatted': {
                'gas_price_wei': standard_gas_price,
                'gas_price_gwei': round(standard_gas_price / 1e9, 2),
                'gas_price_mnt': round(standard_gas_price / 1e18, 8)
            },
            'transaction_costs': {
                'mnt_transfer': standard_gas_price * 21000,  # Standard MNT transfer
                'erc20_transfer': standard_gas_price * 65000,  # Typical ERC20 transfer
                'swap': standard_gas_price * 150000  # Typical DEX swap
            }
        }
    
    def monitor_prices(
        self,
        duration_minutes: int = 60,
        interval_seconds: int = 60
    ) -> Dict[str, Any]:
        """Monitor gas prices over time"""
        
        start_time = datetime.now()
        end_time = start_time + timedelta(minutes=duration_minutes)
        
        print(f"Monitoring gas prices for {duration_minutes} minutes...")
        
        price_data = []
        
        while datetime.now() < end_time:
            try:
                pricing = self.get_comprehensive_pricing()
                price_data.append(pricing)
                self.price_history.append(pricing)
                
                print(f"Price update: {pricing['formatted']['gas_price_gwei']} gwei")
                
                time.sleep(interval_seconds)
                
            except Exception as e:
                print(f"Error monitoring prices: {e}")
                time.sleep(interval_seconds)
        
        return self._analyze_price_data(price_data)
    
    def _analyze_price_data(self, price_data: List[Dict]) -> Dict[str, Any]:
        """Analyze collected price data"""
        
        if not price_data:
            return {'error': 'No price data available'}
        
        gas_prices = [p['standard_gas_price'] for p in price_data]
        gwei_prices = [p['formatted']['gas_price_gwei'] for p in price_data]
        
        analysis = {
            'period': {
                'start': price_data[0]['timestamp'],
                'end': price_data[-1]['timestamp'],
                'data_points': len(price_data)
            },
            'statistics': {
                'min_wei': min(gas_prices),
                'max_wei': max(gas_prices),
                'average_wei': statistics.mean(gas_prices),
                'median_wei': statistics.median(gas_prices),
                'min_gwei': min(gwei_prices),
                'max_gwei': max(gwei_prices),
                'average_gwei': round(statistics.mean(gwei_prices), 2),
                'median_gwei': round(statistics.median(gwei_prices), 2),
                'std_dev_gwei': round(statistics.stdev(gwei_prices) if len(gwei_prices) > 1 else 0, 2)
            },
            'trends': self._calculate_trends(gas_prices),
            'volatility': self._calculate_volatility(gas_prices),
            'cost_analysis': self._analyze_transaction_costs(price_data)
        }
        
        return analysis
    
    def _calculate_trends(self, prices: List[int]) -> Dict[str, Any]:
        """Calculate price trends"""
        
        if len(prices) < 2:
            return {'trend': 'insufficient_data'}
        
        # Simple linear trend
        x = list(range(len(prices)))
        n = len(prices)
        
        # Calculate slope using least squares
        sum_x = sum(x)
        sum_y = sum(prices)
        sum_xy = sum(x[i] * prices[i] for i in range(n))
        sum_x2 = sum(x[i] ** 2 for i in range(n))
        
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        
        # Percentage change
        price_change = prices[-1] - prices[0]
        pct_change = (price_change / prices[0]) * 100
        
        trend_direction = 'increasing' if slope > 0 else 'decreasing' if slope < 0 else 'stable'
        
        return {
            'trend': trend_direction,
            'slope': slope,
            'price_change_wei': price_change,
            'percentage_change': round(pct_change, 2),
            'is_volatile': abs(pct_change) > 10
        }
    
    def _calculate_volatility(self, prices: List[int]) -> Dict[str, Any]:
        """Calculate price volatility metrics"""
        
        if len(prices) < 2:
            return {'volatility': 0}
        
        mean_price = statistics.mean(prices)
        variance = statistics.variance(prices)
        std_dev = statistics.stdev(prices)
        
        # Coefficient of variation (relative volatility)
        cv = (std_dev / mean_price) * 100 if mean_price > 0 else 0
        
        return {
            'standard_deviation': round(std_dev, 2),
            'variance': round(variance, 2),
            'coefficient_of_variation': round(cv, 2),
            'volatility_level': (
                'high' if cv > 15 else
                'medium' if cv > 5 else
                'low'
            )
        }
    
    def _analyze_transaction_costs(self, price_data: List[Dict]) -> Dict[str, Any]:
        """Analyze transaction costs over time"""
        
        cost_analysis = {
            'mnt_transfer': [],
            'erc20_transfer': [],
            'swap': []
        }
        
        for data in price_data:
            costs = data['transaction_costs']
            cost_analysis['mnt_transfer'].append(costs['mnt_transfer'])
            cost_analysis['erc20_transfer'].append(costs['erc20_transfer'])
            cost_analysis['swap'].append(costs['swap'])
        
        result = {}
        for tx_type, costs in cost_analysis.items():
            result[tx_type] = {
                'min_cost_wei': min(costs),
                'max_cost_wei': max(costs),
                'avg_cost_wei': round(statistics.mean(costs)),
                'cost_range_wei': max(costs) - min(costs),
                'min_cost_usd': 'Requires MNT price data',
                'max_cost_usd': 'Requires MNT price data'
            }
        
        return result
    
    def recommend_optimal_timing(
        self,
        target_gas_price_gwei: float,
        transaction_type: str = 'mnt_transfer'
    ) -> Dict[str, Any]:
        """Recommend optimal timing for transaction execution"""
        
        current_pricing = self.get_comprehensive_pricing()
        current_gwei = current_pricing['formatted']['gas_price_gwei']
        
        recommendation = {
            'current_price_gwei': current_gwei,
            'target_price_gwei': target_gas_price_gwei,
            'execute_now': current_gwei <= target_gas_price_gwei
        }
        
        if recommendation['execute_now']:
            recommendation['message'] = 'Current gas price meets target - execute now'
            recommendation['estimated_cost'] = current_pricing['transaction_costs'][transaction_type]
        else:
            price_diff = current_gwei - target_gas_price_gwei
            recommendation['message'] = f'Wait for lower prices (current: {current_gwei}, target: {target_gas_price_gwei})'
            recommendation['price_difference_gwei'] = round(price_diff, 2)
            
            # Simple prediction based on recent trend if available
            if len(self.price_history) > 5:
                recent_prices = [p['standard_gas_price'] for p in self.price_history[-5:]]
                trends = self._calculate_trends(recent_prices)
                
                if trends['trend'] == 'decreasing':
                    recommendation['prediction'] = 'Prices trending down - may reach target soon'
                elif trends['trend'] == 'increasing':
                    recommendation['prediction'] = 'Prices trending up - consider executing soon'
                else:
                    recommendation['prediction'] = 'Prices stable - monitor for changes'
        
        return recommendation
    
    def compare_with_ethereum_l1(self, eth_l1_gas_price_gwei: float) -> Dict[str, Any]:
        """Compare Mantle costs with Ethereum L1"""
        
        mantle_pricing = self.get_comprehensive_pricing()
        mantle_gwei = mantle_pricing['formatted']['gas_price_gwei']
        
        # Calculate savings for different transaction types
        savings_analysis = {}
        
        for tx_type, mantle_gas_units in [
            ('mnt_transfer', 21000),
            ('erc20_transfer', 65000),
            ('swap', 150000)
        ]:
            l1_cost_wei = int(eth_l1_gas_price_gwei * 1e9 * mantle_gas_units)
            mantle_cost_wei = mantle_pricing['transaction_costs'][tx_type]
            
            savings_wei = l1_cost_wei - mantle_cost_wei
            savings_pct = (savings_wei / l1_cost_wei) * 100 if l1_cost_wei > 0 else 0
            
            savings_analysis[tx_type] = {
                'l1_cost_wei': l1_cost_wei,
                'mantle_cost_wei': mantle_cost_wei,
                'savings_wei': savings_wei,
                'savings_percentage': round(savings_pct, 2),
                'cost_ratio': round(mantle_cost_wei / l1_cost_wei, 3) if l1_cost_wei > 0 else 0
            }
        
        return {
            'comparison_timestamp': datetime.now().isoformat(),
            'l1_gas_price_gwei': eth_l1_gas_price_gwei,
            'mantle_gas_price_gwei': mantle_gwei,
            'price_ratio': round(mantle_gwei / eth_l1_gas_price_gwei, 3) if eth_l1_gas_price_gwei > 0 else 0,
            'transaction_savings': savings_analysis
        }

# Usage examples
analyzer = MantleGasPriceAnalyzer('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY')

# Get current comprehensive pricing
pricing = analyzer.get_comprehensive_pricing()
print(f"Current gas price: {pricing['formatted']['gas_price_gwei']} gwei")
print(f"MNT transfer cost: {pricing['transaction_costs']['mnt_transfer']:,} wei")

# Monitor prices for 30 minutes
price_analysis = analyzer.monitor_prices(duration_minutes=30, interval_seconds=120)
print("\nPrice Analysis:")
print(f"Average: {price_analysis['statistics']['average_gwei']} gwei")
print(f"Volatility: {price_analysis['volatility']['volatility_level']}")
print(f"Trend: {price_analysis['trends']['trend']}")

# Get timing recommendation
timing = analyzer.recommend_optimal_timing(target_gas_price_gwei=15.0)
print(f"\nTiming recommendation: {timing['message']}")

# Compare with Ethereum L1 (example with 50 gwei L1 price)
comparison = analyzer.compare_with_ethereum_l1(eth_l1_gas_price_gwei=50.0)
print(f"\nL1 vs Mantle savings:")
for tx_type, data in comparison['transaction_savings'].items():
    print(f"  {tx_type}: {data['savings_percentage']}% savings")
```

## Understanding Gas Prices on Mantle

### Price Components

1. **L2 Gas Price**: Cost per gas unit for execution on Mantle's modular L2
2. **L1 Gas Price**: Current Ethereum L1 gas price for data posting via EigenDA
3. **Overhead**: Fixed overhead cost for L1 data posting
4. **Scalar**: Scaling factor for L1 cost calculation
5. **Decimals**: Decimal precision for calculations

### Cost Calculation

Total transaction cost = (L2 Gas × L2 Gas Price) + L1 Data Fee

Where L1 Data Fee considers:

- Transaction data size
- Current L1 gas price via EigenDA
- Overhead and scalar factors

## Common Use Cases

### 1. Gas Price Monitoring

```javascript
// Monitor gas prices for optimal transaction timing
async function monitorForOptimalGas(targetGwei, callback) {
  const monitor = new MantleGasPriceMonitor(rpcUrl);
  
  const checkPrice = async () => {
    const pricing = await monitor.getCurrentPricing();
    const currentGwei = pricing.formattedPrices.standardGasPrice.gwei;
    
    if (currentGwei <= targetGwei) {
      callback({
        optimal: true,
        currentPrice: currentGwei,
        targetPrice: targetGwei,
        message: 'Target price reached!'
      });
      return true;
    }
    
    return false;
  };
  
  // Check every 30 seconds
  const interval = setInterval(async () => {
    const optimal = await checkPrice();
    if (optimal) {
      clearInterval(interval);
    }
  }, 30000);
  
  // Initial check
  await checkPrice();
}
```

### 2. Cost Optimization

```python
def optimize_transaction_timing(analyzer, transactions, budget_gwei):
    """Find optimal timing for multiple transactions within budget"""
    
    optimization_plan = []
    
    for i, tx in enumerate(transactions):
        # Estimate transaction cost at different gas prices
        cost_estimates = []
        
        for gas_price_gwei in [10, 15, 20, 25, 30]:
            gas_price_wei = int(gas_price_gwei * 1e9)
            estimated_cost = tx['gas_estimate'] * gas_price_wei
            
            cost_estimates.append({
                'gas_price_gwei': gas_price_gwei,
                'estimated_cost_wei': estimated_cost,
                'within_budget': gas_price_gwei <= budget_gwei
            })
        
        # Find optimal price point
        optimal = next(
            (est for est in cost_estimates if est['within_budget']),
            cost_estimates[0]
        )
        
        optimization_plan.append({
            'transaction_id': i,
            'optimal_gas_price': optimal['gas_price_gwei'],
            'estimated_cost': optimal['estimated_cost_wei'],
            'cost_estimates': cost_estimates
        })
    
    return optimization_plan
```

### 3. Historical Analysis

```javascript
// Analyze historical gas price patterns
async function analyzeGasPricePatterns(monitor, days = 7) {
  const patterns = {
    hourlyAverages: {},
    dailyTrends: [],
    optimalTimes: []
  };
  
  // This would require storing historical data
  // For demonstration, showing structure
  
  // Simulate hourly analysis
  for (let hour = 0; hour < 24; hour++) {
    patterns.hourlyAverages[hour] = {
      averageGwei: 0, // Would be calculated from historical data
      transactionVolume: 0,
      volatility: 0
    };
  }
  
  // Identify optimal transaction times
  const sortedHours = Object.entries(patterns.hourlyAverages)
    .sort((a, b) => a[1].averageGwei - b[1].averageGwei);
  
  patterns.optimalTimes = sortedHours.slice(0, 6).map(([hour, data]) => ({
    hour: parseInt(hour),
    averageGwei: data.averageGwei,
    timeRange: `${hour}:00-${hour}:59 UTC`
  }));
  
  return patterns;
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Get current L2 gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/mantle/eth_feeHistory) - Historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/mantle/eth_estimateGas) - Estimate transaction gas
- [`rollup_getInfo`](https://www.dwellir.com/docs/mantle/rollup_getInfo) - Get rollup configuration

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Mantle documentation](https://www.dwellir.com/docs/mantle).*

---

## rollup_getInfo - Get modular L2 rollup config...

# rollup_getInfo - Get modular L2 rollup config...

Get modular L2 rollup configuration on the Mantle network. This method provides essential information about the optimistic rollup parameters, settings, and operational details.

## Overview

Mantle's modular L2 architecture is an optimistic rollup that leverages modular components for enhanced performance and scalability. The rollup configuration includes important parameters for:

- **Batch Processing**: How transactions are batched and processed
- **Data Availability**: EigenDA integration for efficient data posting
- **Bridge Operations**: L1 ↔ L2 asset bridging configuration
- **Network Parameters**: Chain ID, block times, and operational settings

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \\
      -H "Content-Type: application/json" \\
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_getInfo",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup configuration object containing comprehensive information about the modular L2 rollup setup.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "mode": "optimistic",
    "chainId": "0x1388",
    "batchHash": "0x...",
    "stateRoot": "0x...",
    "withdrawalRoot": "0x...",
    "sequencer": "0x...",
    "version": "1.0.0"
  }
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \\
  -H "Content-Type: application/json" \\
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_getInfo",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_getInfo',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Rollup Info:', data.result);

// Advanced Mantle modular L2 rollup information analyzer
class MantleRollupAnalyzer {
  constructor(rpcUrl) {
    this.rpcUrl = rpcUrl;
  }

  async getRollupInfo() {
    const response = await fetch(this.rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'rollup_getInfo',
        params: [],
        id: 1
      })
    });

    const data = await response.json();
    
    if (data.error) {
      throw new Error(`RPC Error: ${data.error.message}`);
    }

    return data.result;
  }

  async getComprehensiveRollupStatus() {
    try {
      // Get rollup info
      const rollupInfo = await this.getRollupInfo();
      
      // Get current chain info
      const chainIdResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_chainId',
          params: [],
          id: 1
        })
      });

      const chainData = await chainIdResponse.json();
      const chainId = parseInt(chainData.result, 16);

      // Get latest block info
      const blockResponse = await fetch(this.rpcUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_getBlockByNumber',
          params: ['latest', false],
          id: 1
        })
      });

      const blockData = await blockResponse.json();
      const latestBlock = blockData.result;

      return {
        timestamp: new Date().toISOString(),
        network: {
          name: 'Mantle',
          chainId: chainId,
          type: 'Modular L2 Optimistic Rollup'
        },
        rollupConfig: rollupInfo,
        currentState: {
          latestBlock: parseInt(latestBlock.number, 16),
          blockHash: latestBlock.hash,
          timestamp: parseInt(latestBlock.timestamp, 16),
          gasLimit: parseInt(latestBlock.gasLimit, 16),
          gasUsed: parseInt(latestBlock.gasUsed, 16),
          utilization: ((parseInt(latestBlock.gasUsed, 16) / parseInt(latestBlock.gasLimit, 16)) * 100).toFixed(2)
        },
        analysis: this.analyzeRollupConfig(rollupInfo, chainId)
      };
    } catch (error) {
      throw new Error(`Failed to get comprehensive status: ${error.message}`);
    }
  }

  analyzeRollupConfig(rollupInfo, chainId) {
    const analysis = {
      networkType: 'Modular L2 Optimistic Rollup',
      securityModel: 'Optimistic with fraud proofs',
      dataAvailability: 'EigenDA integration',
      features: [],
      optimizations: [],
      considerations: []
    };

    // Analyze chain ID
    if (chainId === 5000) {
      analysis.features.push('Mantle Mainnet');
      analysis.features.push('Production Network');
    } else if (chainId === 5003) {
      analysis.features.push('Mantle Sepolia Testnet');
      analysis.features.push('Development Network');
    }

    // General modular L2 features
    analysis.features.push('EVM Compatibility');
    analysis.features.push('Optimistic Rollup Architecture');
    analysis.features.push('EigenDA Data Availability');
    analysis.features.push('MNT Gas Token');
    analysis.features.push('OP Stack Foundation');

    // Optimizations
    analysis.optimizations.push('High Throughput via Modular Architecture');
    analysis.optimizations.push('Low Transaction Costs');
    analysis.optimizations.push('Fast L2 Finality');
    analysis.optimizations.push('Ethereum Virtual Machine Compatibility');
    analysis.optimizations.push('Efficient Data Availability via EigenDA');

    // Considerations
    analysis.considerations.push('7-day withdrawal period for L1 finality');
    analysis.considerations.push('L1 data posting costs via EigenDA');
    analysis.considerations.push('Optimistic fraud proof mechanism');

    return analysis;
  }

  async compareWithOtherL2s() {
    const mantleInfo = await this.getComprehensiveRollupStatus();
    
    // This would be expanded with actual data from other L2s
    const comparison = {
      mantle: {
        type: 'Modular L2 Optimistic Rollup',
        proofSystem: 'Fraud Proofs',
        evmCompatibility: 'Full',
        dataAvailability: 'EigenDA',
        finality: 'Optimistic → Proven',
        withdrawalTime: '~7 days',
        gasToken: 'MNT',
        advantages: [
          'Modular architecture for flexibility',
          'EigenDA for efficient data availability',
          'Fast transaction processing',
          'MNT gas token benefits',
          'OP Stack foundation'
        ]
      },
      zkRollups: {
        type: 'Zero-Knowledge',
        proofSystem: 'Zero-Knowledge Proofs',
        evmCompatibility: 'Full (zkEVM)',
        dataAvailability: 'On-chain (Ethereum L1)',
        finality: 'Cryptographic',
        withdrawalTime: '~7 days (pending finalization)',
        tradeoffs: [
          'Cryptographic security guarantees',
          'Privacy-preserving proofs',
          'Higher computational overhead',
          'Proof generation complexity'
        ]
      },
      comparison: {
        security: 'Both provide strong security with different mechanisms',
        performance: 'Mantle optimized for high throughput',
        costs: 'Mantle benefits from EigenDA cost efficiency',
        devExperience: 'Both offer full EVM compatibility'
      }
    };

    return comparison;
  }

  async monitorRollupHealth() {
    const health = {
      timestamp: new Date().toISOString(),
      status: 'unknown',
      metrics: {},
      alerts: []
    };

    try {
      const status = await this.getComprehensiveRollupStatus();
      
      // Check basic connectivity and latest block
      const blockAge = Date.now() / 1000 - status.currentState.timestamp;
      
      health.metrics = {
        latestBlock: status.currentState.latestBlock,
        blockAge: blockAge,
        gasUtilization: parseFloat(status.currentState.utilization),
        chainId: status.network.chainId
      };

      // Health checks
      if (blockAge > 300) { // 5 minutes
        health.alerts.push({
          severity: 'warning',
          message: `Latest block is ${Math.floor(blockAge / 60)} minutes old`,
          recommendation: 'Check network connectivity and block production'
        });
      }

      if (health.metrics.gasUtilization > 90) {
        health.alerts.push({
          severity: 'info',
          message: `High gas utilization: ${health.metrics.gasUtilization}%`,
          recommendation: 'Network is experiencing high usage'
        });
      }

      health.status = health.alerts.length === 0 ? 'healthy' : 
                    health.alerts.some(a => a.severity === 'error') ? 'unhealthy' : 'warning';

    } catch (error) {
      health.status = 'error';
      health.alerts.push({
        severity: 'error',
        message: `Failed to get rollup status: ${error.message}`,
        recommendation: 'Check RPC endpoint connectivity'
      });
    }

    return health;
  }

  async getNetworkCapacityInfo() {
    try {
      const status = await this.getComprehensiveRollupStatus();
      
      const capacity = {
        current: {
          blockGasLimit: status.currentState.gasLimit,
          blockGasUsed: status.currentState.gasUsed,
          utilizationPercentage: parseFloat(status.currentState.utilization)
        },
        theoretical: {
          maxTxPerSecond: 0, // Would be calculated based on average gas per tx
          maxTxPerBlock: 0,
          avgBlockTime: 0 // Would need historical data
        },
        estimates: {
          simpleTransfers: Math.floor(status.currentState.gasLimit / 21000),
          erc20Transfers: Math.floor(status.currentState.gasLimit / 65000),
          complexContracts: Math.floor(status.currentState.gasLimit / 200000)
        }
      };

      return capacity;
    } catch (error) {
      throw new Error(`Failed to get capacity info: ${error.message}`);
    }
  }

  async analyzeUpgradeability() {
    const rollupInfo = await this.getRollupInfo();
    
    // This would analyze the actual rollup configuration
    // For demonstration, providing general modular L2 upgrade analysis
    return {
      upgradeType: 'Governed Upgrades',
      governanceModel: 'Multi-signature or DAO governance',
      upgradeProcess: [
        'Proposal submission',
        'Community review',
        'Governance voting',
        'Implementation timeline',
        'Upgrade execution'
      ],
      considerations: [
        'Modular architecture allows component upgrades',
        'Smart contract upgrades follow standard patterns',
        'L1 contract upgrades need careful coordination',
        'Backward compatibility maintenance'
      ],
      riskMitigation: [
        'Extensive testing on testnets',
        'Gradual rollout procedures',
        'Emergency pause mechanisms',
        'Rollback capabilities where possible'
      ]
    };
  }

  async getBridgeInfo() {
    // This would integrate with bridge contracts
    // For demonstration, providing general bridge information
    return {
      bridgeType: 'Canonical Bridge',
      supportedAssets: [
        'ETH (bridged)',
        'MNT (native gas token)',
        'ERC-20 Tokens',
        'ERC-721 NFTs',
        'ERC-1155 Multi-tokens'
      ],
      bridgeProcess: {
        deposit: {
          timeToL2: '~15 minutes',
          steps: [
            'Lock tokens on L1',
            'Wait for L1 confirmation',
            'Mint on L2',
            'Tokens available on L2'
          ]
        },
        withdrawal: {
          timeToL1: '~7 days',
          steps: [
            'Burn tokens on L2',
            'Include in batch',
            'Submit to L1',
            'Challenge period (7 days)',
            'Claim on L1'
          ]
        }
      },
      security: {
        model: 'Optimistic fraud proofs',
        assumptions: 'Ethereum L1 security + honest validator assumption',
        risks: [
          'Smart contract bugs',
          'Fraud proof mechanism vulnerabilities',
          'Bridge implementation issues'
        ]
      }
    };
  }
}

// Usage examples
const rollupAnalyzer = new MantleRollupAnalyzer('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get basic rollup info
const rollupInfo = await rollupAnalyzer.getRollupInfo();
console.log('Rollup Configuration:', rollupInfo);

// Get comprehensive status
const comprehensiveStatus = await rollupAnalyzer.getComprehensiveRollupStatus();
console.log('Network Status:', comprehensiveStatus);

// Monitor rollup health
const healthStatus = await rollupAnalyzer.monitorRollupHealth();
console.log('Health Status:', healthStatus.status);
console.log('Alerts:', healthStatus.alerts);

// Get network capacity info
const capacityInfo = await rollupAnalyzer.getNetworkCapacityInfo();
console.log('Network Capacity:', capacityInfo);

// Compare with other L2s
const comparison = await rollupAnalyzer.compareWithOtherL2s();
console.log('L2 Comparison:', comparison);

// Analyze upgradeability
const upgradeAnalysis = await rollupAnalyzer.analyzeUpgradeability();
console.log('Upgrade Model:', upgradeAnalysis);

// Get bridge information
const bridgeInfo = await rollupAnalyzer.getBridgeInfo();
console.log('Bridge Details:', bridgeInfo);
```

```python
import requests
import json
import time
from typing import Dict, List, Any, Optional
from datetime import datetime

class MantleRollupInfoAnalyzer:
    """Comprehensive analyzer for Mantle modular L2 rollup information"""
    
    def __init__(self, rpc_url: str):
        self.rpc_url = rpc_url
    
    def get_rollup_info(self) -> Dict[str, Any]:
        """Get basic rollup configuration information"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": "rollup_getInfo",
            "params": [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def _make_rpc_call(self, method: str, params: List = None) -> Any:
        """Helper method for making RPC calls"""
        
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params or [],
            "id": 1
        }
        
        response = requests.post(self.rpc_url, json=payload)
        data = response.json()
        
        if 'error' in data:
            raise Exception(f"RPC Error: {data['error']['message']}")
        
        return data['result']
    
    def get_comprehensive_rollup_status(self) -> Dict[str, Any]:
        """Get comprehensive rollup status and configuration"""
        
        rollup_info = self.get_rollup_info()
        
        # Get additional network information
        chain_id = int(self._make_rpc_call('eth_chainId'), 16)
        latest_block = self._make_rpc_call('eth_getBlockByNumber', ['latest', False])
        
        block_number = int(latest_block['number'], 16)
        block_timestamp = int(latest_block['timestamp'], 16)
        gas_limit = int(latest_block['gasLimit'], 16)
        gas_used = int(latest_block['gasUsed'], 16)
        
        return {
            'timestamp': datetime.now().isoformat(),
            'network_info': {
                'name': 'Mantle',
                'chain_id': chain_id,
                'type': 'Modular L2 Optimistic Rollup',
                'consensus': 'Optimistic with fraud proofs'
            },
            'rollup_config': rollup_info,
            'current_state': {
                'latest_block': block_number,
                'block_hash': latest_block['hash'],
                'block_timestamp': block_timestamp,
                'gas_limit': gas_limit,
                'gas_used': gas_used,
                'gas_utilization': round((gas_used / gas_limit) * 100, 2),
                'block_age_seconds': int(time.time()) - block_timestamp
            },
            'analysis': self._analyze_rollup_configuration(rollup_info, chain_id)
        }
    
    def _analyze_rollup_configuration(
        self, 
        rollup_info: Dict[str, Any], 
        chain_id: int
    ) -> Dict[str, Any]:
        """Analyze rollup configuration and provide insights"""
        
        analysis = {
            'rollup_type': 'Modular L2 Optimistic Rollup',
            'security_model': 'Optimistic fraud proofs with L1 data availability',
            'key_features': [
                'Full EVM compatibility',
                'Optimistic fraud proof validation',
                'EigenDA data availability',
                'MNT gas token',
                'OP Stack foundation',
                'Modular architecture'
            ],
            'network_classification': 'Mainnet' if chain_id == 5000 else 'Testnet',
            'performance_characteristics': {
                'finality': 'Optimistic with 7-day challenge period',
                'withdrawal_time': '~7 days (challenge period)',
                'throughput': 'High (optimized via modular architecture)',
                'costs': 'Low L2 execution + efficient L1 data costs via EigenDA'
            }
        }
        
        # Add specific insights based on chain
        if chain_id == 5000:  # Mantle Mainnet
            analysis['environment'] = 'Production'
            analysis['considerations'] = [
                'Real value at risk',
                'Production-grade security',
                'Full audit coverage',
                'Mainnet gas costs with MNT token'
            ]
        elif chain_id == 5003:  # Mantle Sepolia Testnet
            analysis['environment'] = 'Testing'
            analysis['considerations'] = [
                'Testing and development use',
                'No real value',
                'Latest features may be experimental',
                'Network resets possible'
            ]
        
        return analysis
    
    def monitor_rollup_performance(self, duration_minutes: int = 10) -> Dict[str, Any]:
        """Monitor rollup performance over time"""
        
        monitoring_data = []
        start_time = datetime.now()
        
        print(f"Monitoring rollup for {duration_minutes} minutes...")
        
        try:
            while (datetime.now() - start_time).seconds < duration_minutes * 60:
                status = self.get_comprehensive_rollup_status()
                monitoring_data.append(status)
                
                print(f"Block: {status['current_state']['latest_block']}, "
                      f"Utilization: {status['current_state']['gas_utilization']}%")
                
                time.sleep(30)  # Check every 30 seconds
                
        except KeyboardInterrupt:
            print("Monitoring stopped by user")
        
        return self._analyze_performance_data(monitoring_data)
    
    def _analyze_performance_data(self, monitoring_data: List[Dict]) -> Dict[str, Any]:
        """Analyze collected performance data"""
        
        if not monitoring_data:
            return {'error': 'No monitoring data collected'}
        
        block_numbers = [d['current_state']['latest_block'] for d in monitoring_data]
        gas_utilizations = [d['current_state']['gas_utilization'] for d in monitoring_data]
        block_ages = [d['current_state']['block_age_seconds'] for d in monitoring_data]
        
        # Calculate block production rate
        if len(block_numbers) > 1:
            blocks_produced = block_numbers[-1] - block_numbers[0]
            time_elapsed = (
                datetime.fromisoformat(monitoring_data[-1]['timestamp']) -
                datetime.fromisoformat(monitoring_data[0]['timestamp'])
            ).seconds
            avg_block_time = time_elapsed / blocks_produced if blocks_produced > 0 else 0
        else:
            avg_block_time = 0
            blocks_produced = 0
        
        return {
            'monitoring_period': {
                'start': monitoring_data[0]['timestamp'],
                'end': monitoring_data[-1]['timestamp'],
                'data_points': len(monitoring_data)
            },
            'block_production': {
                'blocks_produced': blocks_produced,
                'average_block_time': round(avg_block_time, 2),
                'block_range': f"{block_numbers[0]} - {block_numbers[-1]}"
            },
            'gas_utilization': {
                'average': round(sum(gas_utilizations) / len(gas_utilizations), 2),
                'min': min(gas_utilizations),
                'max': max(gas_utilizations),
                'trend': self._calculate_trend(gas_utilizations)
            },
            'network_health': {
                'consistent_block_production': blocks_produced > 0,
                'average_block_age': round(sum(block_ages) / len(block_ages), 2),
                'health_score': self._calculate_health_score(monitoring_data)
            }
        }
    
    def _calculate_trend(self, values: List[float]) -> str:
        """Calculate trend direction for a series of values"""
        
        if len(values) < 2:
            return 'insufficient_data'
        
        first_half = values[:len(values)//2]
        second_half = values[len(values)//2:]
        
        first_avg = sum(first_half) / len(first_half)
        second_avg = sum(second_half) / len(second_half)
        
        change_pct = ((second_avg - first_avg) / first_avg) * 100 if first_avg > 0 else 0
        
        if change_pct > 5:
            return 'increasing'
        elif change_pct < -5:
            return 'decreasing'
        else:
            return 'stable'
    
    def _calculate_health_score(self, monitoring_data: List[Dict]) -> float:
        """Calculate a health score for the rollup"""
        
        score = 100.0
        
        # Check for stale blocks
        avg_block_age = sum(d['current_state']['block_age_seconds'] for d in monitoring_data) / len(monitoring_data)
        if avg_block_age > 300:  # 5 minutes
            score -= 20
        elif avg_block_age > 120:  # 2 minutes
            score -= 10
        
        # Check gas utilization patterns
        gas_utils = [d['current_state']['gas_utilization'] for d in monitoring_data]
        avg_util = sum(gas_utils) / len(gas_utils)
        
        if avg_util > 95:  # Very high utilization
            score -= 15
        elif avg_util < 5:  # Very low utilization (might indicate issues)
            score -= 10
        
        return max(0, score)
    
    def compare_with_ethereum_l1(self, eth_l1_rpc_url: str = None) -> Dict[str, Any]:
        """Compare Mantle with Ethereum L1 characteristics"""
        
        mantle_status = self.get_comprehensive_rollup_status()
        
        comparison = {
            'mantle_modular_l2': {
                'type': 'Modular L2 Optimistic Rollup',
                'consensus': 'Optimistic fraud proofs',
                'finality': 'Optimistic → Proven (7 days)',
                'block_time': '~2 seconds',
                'gas_limit': mantle_status['current_state']['gas_limit'],
                'gas_token': 'MNT',
                'transaction_throughput': 'High',
                'transaction_costs': 'Low'
            },
            'ethereum_l1': {
                'type': 'Layer 1 Blockchain',
                'consensus': 'Proof of Stake',
                'finality': 'Probabilistic',
                'block_time': '~12 seconds',
                'gas_limit': '~30M gas',
                'gas_token': 'ETH',
                'transaction_throughput': 'Limited',
                'transaction_costs': 'High'
            },
            'advantages_mantle': [
                'Lower transaction costs with MNT token',
                'Higher throughput via modular architecture',
                'EVM compatibility',
                'Inherits Ethereum security',
                'EigenDA data availability efficiency',
                'OP Stack foundation'
            ],
            'advantages_l1': [
                'No additional trust assumptions',
                'Direct composability',
                'Immediate finality',
                'No bridge requirements',
                'Maximum decentralization'
            ]
        }
        
        return comparison
    
    def analyze_upgradeability_governance(self) -> Dict[str, Any]:
        """Analyze upgradeability and governance mechanisms"""
        
        return {
            'upgrade_mechanism': 'Governed Smart Contracts',
            'governance_model': {
                'type': 'Multi-signature or DAO governance',
                'participants': [
                    'Core development team',
                    'Community stakeholders',
                    'Security auditors',
                    'Ecosystem partners'
                ]
            },
            'upgrade_process': {
                'steps': [
                    '1. Proposal creation and review',
                    '2. Community discussion period',
                    '3. Technical evaluation',
                    '4. Governance voting',
                    '5. Implementation timeline',
                    '6. Staged rollout',
                    '7. Post-upgrade monitoring'
                ],
                'timeframes': {
                    'discussion_period': '1-2 weeks',
                    'voting_period': '1 week',
                    'implementation_delay': '1-2 weeks',
                    'total_process': '4-6 weeks minimum'
                }
            },
            'risk_mitigation': [
                'Extensive testnet validation',
                'Audit requirements',
                'Emergency pause mechanisms',
                'Gradual feature activation',
                'Rollback procedures where possible'
            ],
            'recent_upgrades': 'Check governance forum for latest information'
        }
    
    def get_bridge_integration_info(self) -> Dict[str, Any]:
        """Get information about bridge integrations and interoperability"""
        
        return {
            'canonical_bridge': {
                'purpose': 'Official L1 ↔ L2 asset transfer',
                'supported_assets': [
                    'ETH (bridged from Ethereum)',
                    'MNT (native gas token)',
                    'ERC-20 tokens',
                    'ERC-721 NFTs',
                    'ERC-1155 multi-tokens'
                ],
                'security_model': 'Optimistic fraud proof validation'
            },
            'bridge_process': {
                'deposits_l1_to_l2': {
                    'time': '~15 minutes',
                    'process': [
                        'Lock assets on L1',
                        'Wait for L1 confirmation',
                        'Automatic minting on L2',
                        'Assets available on L2'
                    ]
                },
                'withdrawals_l2_to_l1': {
                    'time': '~7 days',
                    'process': [
                        'Burn assets on L2',
                        'Include in batch',
                        'Submit to L1',
                        'Challenge period (7 days)',
                        'Claim assets on L1'
                    ]
                }
            },
            'third_party_bridges': {
                'availability': 'Multiple third-party bridge providers',
                'considerations': [
                    'Different security models',
                    'Varying withdrawal times',
                    'Different supported assets',
                    'Additional trust assumptions'
                ]
            }
        }

# Usage examples
analyzer = MantleRollupInfoAnalyzer('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY')

# Get basic rollup information
rollup_info = analyzer.get_rollup_info()
print("Basic Rollup Info:", json.dumps(rollup_info, indent=2))

# Get comprehensive status
comprehensive_status = analyzer.get_comprehensive_rollup_status()
print(f"\nNetwork: {comprehensive_status['network_info']['name']}")
print(f"Chain ID: {comprehensive_status['network_info']['chain_id']}")
print(f"Latest Block: {comprehensive_status['current_state']['latest_block']}")
print(f"Gas Utilization: {comprehensive_status['current_state']['gas_utilization']}%")

# Analyze network type
analysis = comprehensive_status['analysis']
print(f"\nRollup Type: {analysis['rollup_type']}")
print(f"Environment: {analysis['environment']}")
print("Key Features:")
for feature in analysis['key_features']:
    print(f"  - {feature}")

# Monitor performance (short demo)
print("\nStarting performance monitoring...")
performance_data = analyzer.monitor_rollup_performance(duration_minutes=2)
print("Performance Analysis:")
print(f"  Average block time: {performance_data['block_production']['average_block_time']}s")
print(f"  Health score: {performance_data['network_health']['health_score']}/100")

# Compare with L1
comparison = analyzer.compare_with_ethereum_l1()
print("\nMantle Advantages:")
for advantage in comparison['advantages_mantle']:
    print(f"  - {advantage}")

# Governance analysis
governance = analyzer.analyze_upgradeability_governance()
print(f"\nGovernance Model: {governance['governance_model']['type']}")
print(f"Upgrade Process Duration: {governance['upgrade_process']['timeframes']['total_process']}")

# Bridge information
bridge_info = analyzer.get_bridge_integration_info()
print(f"\nBridge Withdrawal Time: {bridge_info['bridge_process']['withdrawals_l2_to_l1']['time']}")
print("Supported Assets:")
for asset in bridge_info['canonical_bridge']['supported_assets']:
    print(f"  - {asset}")
```

## Understanding Mantle Modular L2 Configuration

### Key Components

1. **Mode**: Operating mode of the rollup (optimistic)
2. **Chain ID**: Network identifier (5000 for mainnet, 5003 for testnet)
3. **State Root**: Root hash of the current state tree
4. **Batch Hash**: Hash of the current batch of transactions
5. **Sequencer**: Address of the transaction sequencing system
6. **Version**: Current version of the rollup implementation

### Modular L2 Architecture

- **Sequencing**: Optimistic transaction ordering and execution
- **Data Availability**: EigenDA integration for efficient data posting
- **EVM Compatibility**: Full compatibility with Ethereum Virtual Machine
- **Finality**: Fast L2 finality with 7-day challenge period for L1 finality

## Common Use Cases

### 1. Network Health Monitoring

```javascript
// Monitor rollup health and performance
async function monitorRollupHealth(analyzer) {
  const healthCheck = async () => {
    const status = await analyzer.getComprehensiveRollupStatus();
    
    const alerts = [];
    
    // Check block production
    if (status.current_state.block_age_seconds > 300) {
      alerts.push({
        type: 'stale_blocks',
        severity: 'warning',
        message: 'Blocks are older than expected'
      });
    }
    
    // Check gas utilization
    if (status.current_state.gas_utilization > 95) {
      alerts.push({
        type: 'high_utilization',
        severity: 'info',
        message: 'Network experiencing high usage'
      });
    }
    
    return {
      status: alerts.length === 0 ? 'healthy' : 'warning',
      alerts: alerts,
      metrics: status.current_state
    };
  };
  
  return healthCheck;
}
```

### 2. Integration Compatibility Check

```python
def check_integration_compatibility(analyzer):
    """Check if current rollup config is compatible with integration"""
    
    status = analyzer.get_comprehensive_rollup_status()
    rollup_info = status['rollup_config']
    
    compatibility = {
        'evm_compatible': True,  # Modular L2 is fully EVM compatible
        'supported_features': [
            'Standard Ethereum transactions',
            'Smart contract deployment',
            'ERC token standards',
            'Event emission and filtering',
            'eth_call and eth_estimateGas',
            'Debug and trace methods'
        ],
        'limitations': [
            '7-day withdrawal period for L1 finality',
            'L1 data posting affects costs',
            'Optimistic fraud proof mechanism'
        ],
        'recommended_practices': [
            'Use standard Ethereum tooling',
            'Account for withdrawal delays',
            'Monitor gas price fluctuations with MNT token',
            'Leverage EigenDA data availability benefits'
        ]
    }
    
    return compatibility
```

### 3. Performance Benchmarking

```javascript
// Benchmark rollup performance characteristics
async function benchmarkRollupPerformance(analyzer) {
  const benchmark = {
    testDuration: '10 minutes',
    metrics: {},
    recommendations: []
  };
  
  // Monitor for performance data
  const performanceData = await analyzer.monitorRollupPerformance(10);
  
  benchmark.metrics = {
    avgBlockTime: performanceData.block_production.average_block_time,
    gasUtilization: performanceData.gas_utilization.average,
    healthScore: performanceData.network_health.health_score
  };
  
  // Generate recommendations
  if (benchmark.metrics.avgBlockTime > 5) {
    benchmark.recommendations.push(
      'Block times are longer than expected - monitor network congestion'
    );
  }
  
  if (benchmark.metrics.gasUtilization > 80) {
    benchmark.recommendations.push(
      'High gas utilization - consider transaction timing optimization'
    );
  }
  
  return benchmark;
}
```

## Integration Considerations

### Development

- **Tooling**: Use standard Ethereum development tools (Hardhat, Truffle, Remix)
- **RPC Compatibility**: Full JSON-RPC compatibility with additional rollup-specific methods
- **Gas Estimation**: Account for MNT gas token and EigenDA data costs

### Production Deployment

- **Security**: Leverage optimistic rollup security with fraud proofs
- **Monitoring**: Monitor both L2 state and L1 batch submission
- **Bridge Integration**: Plan for canonical bridge usage and withdrawal delays

### User Experience

- **Transaction Speed**: Fast L2 confirmation with 7-day L1 finality
- **Cost Optimization**: Benefit from MNT gas token and EigenDA efficiency
- **Bridge UX**: Clear communication about withdrawal timeframes

## Related Methods

- [`rollup_gasPrices`](https://www.dwellir.com/docs/mantle/rollup_gasPrices) - Get gas price oracle data
- [`eth_chainId`](https://www.dwellir.com/docs/mantle/eth_chainId) - Get network chain ID
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/mantle/eth_getBlockByNumber) - Get block information

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Mantle documentation](https://www.dwellir.com/docs/mantle).*

---

## rpc_modules - Mantle RPC Method

# rpc_modules - Mantle RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Mantle endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/mantle/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/mantle/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Mantle RPC Method

# txpool_content - Mantle RPC Method

Returns the full pending and queued transaction pool for the connected Mantle endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`txpool_content` is useful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/mantle/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/mantle/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/mantle/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Mantle RPC Method

# txpool_status - Mantle RPC Method

Returns transaction pool counters for the connected Mantle endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`txpool_status` is valuable for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/mantle/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/mantle/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/mantle/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Mantle RPC Method

# web3_clientVersion - Mantle RPC Method

Returns the current client software version string for your Mantle node, including the client name, version number, OS, and runtime.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Mantle client:', clientVersion);

// Using fetch
const response = await fetch('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Mantle client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Mantle client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/mantle/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/mantle/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/mantle/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/mantle/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Mantle RPC Method

# web3_sha3 - Mantle RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Mantle.

> **Why Mantle?** Build on the world's largest ZK rollup by TVL with $2.5B+ secured and deep Bybit integration with near-instant ZK finality via OP Succinct, $6.2B treasury backing, mETH liquid staking, and 25% Bybit trading fee discounts.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, liquid staking builders, and teams seeking institutional exchange integration:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-mantle-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/mantle/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/mantle/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/mantle/web3_clientVersion) - Get node client version

---

## MegaETH - The First Real-Time Blockchain

# MegaETH - The First Real-Time Blockchain

## MegaETH RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where MegaETH supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on MegaETH?

MegaETH is the world's first real-time blockchain, delivering unprecedented performance while maintaining full EVM compatibility:

### **Real-Time Performance**

- **Sub-millisecond latency** - Transaction streaming in real-time, not batches
- **100,000+ TPS sustained** - Orders of magnitude faster than traditional L2s
- **0.01 second block time** - Near-instant transaction finality

### **Battle-Tested Security**

- **Ethereum-secured** - Inherits Ethereum's L1 security guarantees
- **Backed by Vitalik Buterin** - Co-founded by Ethereum's creator
- **Full EVM compatibility** - All existing Ethereum tools work seamlessly

### **Ideal for High-Frequency Applications**

- **High-frequency DeFi** - Enable latency-sensitive trading strategies
- **Gaming & Real-Time Apps** - Build truly responsive onchain experiences
- **Instant UX** - Deliver web2-like responsiveness with web3 security

## Quick Start with MegaETH

Connect to MegaETH in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to MegaETH mainnet
const provider = new JsonRpcProvider(
  'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to MegaETH mainnet
const web3 = new Web3(
  'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to MegaETH:', chainId === 4326);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { defineChain } from 'viem';

// Define MegaETH chain
const megaeth = defineChain({
  id: 4326,
  name: 'MegaETH',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'] },
  },
  blockExplorers: {
    default: { name: 'Blockscout', url: 'https://megaeth.blockscout.com' },
  },
});

// Create MegaETH client
const client = createPublicClient({
  chain: megaeth,
  transport: http('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value        | Details      |
| ------------ | ------------ | ------------ |
| Chain ID     | 4326         | Mainnet      |
| Block Time   | 0.01 seconds | Real-time    |
| Gas Token    | ETH          | Native token |
| RPC Standard | Ethereum     | JSON-RPC 2.0 |

## API Reference

MegaETH supports a subset of the [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) optimized for real-time performance.

MegaETH implements core Ethereum JSON-RPC methods with some modifications for performance:

- **Debug methods** are not available (debug\_*, trace\_*)
- **Full block queries** are disabled for `eth_getBlockByHash` and `eth_getBlockByNumber`
- **Gas limits** apply to certain methods (10,000,000 gas for `eth_call`, `eth_createAccessList`, `eth_estimateGas`)
- **Block range limits** apply to `eth_feeHistory` (maximum 10,000 blocks)

## Common Integration Patterns

### Real-Time Transaction Streaming

Leverage MegaETH's real-time capabilities for instant transaction updates:

```javascript
// Subscribe to pending transactions via WebSocket
const wsProvider = new ethers.WebSocketProvider(
  'wss://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Watch for new blocks in real-time (every 0.01s)
wsProvider.on('block', async (blockNumber) => {
  console.log('New block:', blockNumber);
  const block = await wsProvider.getBlock(blockNumber);
  console.log('Block timestamp:', block.timestamp);
});

// Watch for specific transaction confirmations
async function streamTransaction(txHash) {
  const receipt = await wsProvider.waitForTransaction(txHash, 1);
  console.log('Transaction confirmed in:', receipt.blockNumber);
  return receipt;
}
```

### Gas Optimization

Optimize gas costs on MegaETH:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Calculate total cost
const totalCost = gasEstimate * feeData.gasPrice;
console.log('Estimated cost:', totalCost);
```

### Event Filtering

Efficiently query contract events with MegaETH's fast block times:

```javascript
// Query recent events (fast with 0.01s blocks)
async function getRecentEvents(contract, eventName, blocksBack = 1000) {
  const latestBlock = await provider.getBlockNumber();
  const fromBlock = latestBlock - blocksBack;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, latestBlock);

  return events;
}
```

## Performance Best Practices

### 1. **WebSocket for Real-Time Updates**

Use WebSockets to leverage MegaETH's real-time streaming capabilities:

```javascript
const wsProvider = new ethers.WebSocketProvider(
  'wss://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Subscribe to new blocks (every 0.01s)
wsProvider.on('block', (blockNumber) => {
  console.log('New block:', blockNumber);
});

// Handle reconnection
wsProvider.on('error', () => {
  console.log('WebSocket error, reconnecting...');
});
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class MegaETHProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Respect Gas Limits**

MegaETH enforces a 10,000,000 gas limit for certain methods:

```javascript
// When calling contracts, stay within gas limits
const result = await provider.call({
  to: contractAddress,
  data: calldata,
  // MegaETH enforces 10M gas limit
  gasLimit: 10000000
});
```

## Troubleshooting Common Issues

### Error: "Gas limit exceeded"

MegaETH limits certain methods to 10,000,000 gas:

```javascript
// Split large queries into smaller batches
async function batchCall(contract, method, args, batchSize = 100) {
  const results = [];
  for (let i = 0; i < args.length; i += batchSize) {
    const batch = args.slice(i, i + batchSize);
    const result = await contract[method](https://www.dwellir.com/docs/batch);
    results.push(...result);
  }
  return results;
}
```

### Error: "Full block queries disabled"

Use the standard block query format without transaction details:

```javascript
// Don't request full transaction objects
const block = await provider.getBlock(blockNumber, false);

// If you need transaction details, fetch them separately
for (const txHash of block.transactions) {
  const tx = await provider.getTransaction(txHash);
  console.log('Transaction:', tx);
}
```

### Error: "Block range too large"

For `eth_feeHistory`, limit your range to 10,000 blocks:

```javascript
// Query fee history in 10k block batches
async function getFeeHistory(blockCount, newestBlock) {
  const maxRange = 10000;
  if (blockCount > maxRange) {
    // Split into multiple requests
    const batches = Math.ceil(blockCount / maxRange);
    const results = [];
    for (let i = 0; i < batches; i++) {
      const batchSize = Math.min(maxRange, blockCount - (i * maxRange));
      const batchResult = await provider.send('eth_feeHistory', [
        batchSize,
        newestBlock - (i * maxRange),
        []
      ]);
      results.push(batchResult);
    }
    return results;
  }
  return provider.send('eth_feeHistory', [blockCount, newestBlock, []]);
}
```

## Smoke Tests

### Test Connection with cURL

```bash
# Test MegaETH mainnet
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Test with Ethers.js

```javascript
// Test mainnet connection
const mainnetProvider = new JsonRpcProvider(
  'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const blockNumber = await mainnetProvider.getBlockNumber();
const network = await mainnetProvider.getNetwork();

console.log('Block number:', blockNumber);
console.log('Chain ID:', network.chainId); // Should be 4326n
```

### Test with Web3.py

```python
from web3 import Web3

# Test connection
web3 = Web3(Web3.HTTPProvider(
  'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
))

print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # Should be 4326
print('Block number:', web3.eth.block_number)
```

## Migration Guide

### From Other EVM Chains

MegaETH is fully EVM-compatible, making migration straightforward:

```javascript
// Before (Ethereum/other L2)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (MegaETH)
const provider = new JsonRpcProvider(
  'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (4326)
// Note: Some debug methods unavailable
// Note: Gas limits apply (10M for call/estimateGas)
// Note: Full block queries disabled
```

## Resources & Tools

### Official Resources

- [MegaETH Documentation](https://docs.megaeth.com/)
- [MegaETH Website](https://www.megaeth.com)
- [MegaETH Block Explorer](https://megaeth.blockscout.com/)

### Developer Tools

- [Hardhat](https://hardhat.org/) - Full EVM compatibility
- [Foundry](https://getfoundry.sh/) - Fast Solidity testing
- [Truffle](https://trufflesuite.com/) - Development framework

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on MegaETH with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## eth_accounts - MegaETH RPC Method

# eth_accounts - MegaETH RPC Method

Returns a list of addresses owned by the client on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for high-frequency DeFi developers, gaming studios, and teams building real-time applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/megaeth/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/megaeth/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - MegaETH RPC Method

# eth_blockNumber - MegaETH RPC Method

Returns the number of the most recent block on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_blockNumber` is fundamental for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Syncing Applications** - Keep your dApp in sync with the latest MegaETH blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('MegaETH block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('MegaETH block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'MegaETH block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'MegaETH block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("MegaETH block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on MegaETH:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on MegaETH:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your MegaETH node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/megaeth/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/megaeth/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/megaeth/eth_syncing) - Check if node is still syncing

---

## eth_call - MegaETH RPC Method

# eth_call - MegaETH RPC Method

Executes a new message call immediately without creating a transaction on MegaETH. Used for reading smart contract state.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

The `eth_call` method serves these key scenarios for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on MegaETH
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';
const walletAddress = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on MegaETH. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Gas Limit Restriction

On MegaETH, `eth_call` requests are subject to a **maximum gas limit of 10,000,000**. This limit ensures optimal real-time performance across the network.

If your contract call requires more gas, consider:

- Breaking the operation into smaller calls
- Optimizing your smart contract logic
- Using view functions that return aggregated data

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on MegaETH
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on MegaETH

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x1F006CCc9Ac133035D8B9bb17E5739E6a17E8C51",
      "data": "0x06fdde03"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Call ERC20 name() function
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x1F006CCc9Ac133035D8B9bb17E5739E6a17E8C51",
      "data": "0x06fdde03"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common read functions
const ERC20_ABI = [
  "function name() view returns (string)",
  "function symbol() view returns (string)",
  "function decimals() view returns (uint8)",
  "function totalSupply() view returns (uint256)",
  "function balanceOf(address owner) view returns (uint256)"
];

// Read token information
const tokenAddress = '0x1F006CCc9Ac133035D8B9bb17E5739E6a17E8C51';
const contract = new Contract(tokenAddress, ERC20_ABI, provider);

// Get token name
const name = await contract.name();
console.log('Token name:', name);

// Get token symbol and decimals
const symbol = await contract.symbol();
const decimals = await contract.decimals();
console.log(`Token: ${symbol}, Decimals: ${decimals}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# ERC20 token ABI for common functions
ERC20_ABI = [
    {
        "constant": True,
        "inputs": [],
        "name": "name",
        "outputs": [{"name": "", "type": "string"}],
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [],
        "name": "symbol",
        "outputs": [{"name": "", "type": "string"}],
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [],
        "name": "decimals",
        "outputs": [{"name": "", "type": "uint8"}],
        "type": "function"
    }
]

# Create contract instance
token_address = '0x1F006CCc9Ac133035D8B9bb17E5739E6a17E8C51'
contract = w3.eth.contract(address=token_address, abi=ERC20_ABI)

# Call name() function
name = contract.functions.name().call()
print(f'Token name: {name}')

# Get additional token info
symbol = contract.functions.symbol().call()
decimals = contract.functions.decimals().call()
print(f'Token: {symbol}, Decimals: {decimals}')
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/megaeth/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - MegaETH RPC Method

# eth_chainId - MegaETH RPC Method

Returns the chain ID used for transaction signing on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_chainId` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/megaeth/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/megaeth/eth_syncing) - Check sync status

---

## eth_coinbase - MegaETH RPC Method

# eth_coinbase - MegaETH RPC Method

Checks the legacy `eth_coinbase` compatibility method on MegaETH. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for high-frequency DeFi developers, gaming studios, and teams building real-time applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('MegaETH coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('MegaETH coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'MegaETH coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'MegaETH coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("MegaETH coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of MegaETH nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/megaeth/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/megaeth/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/megaeth/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - MegaETH RPC Method

# eth_estimateGas - MegaETH RPC Method

Estimates the gas necessary to execute a transaction on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on MegaETH
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on MegaETH.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like MegaETH may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
  '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
  '0.01'
);
```

## Gas Limit Restriction

On MegaETH, `eth_estimateGas` requests are subject to a **maximum gas limit of 10,000,000**. Complex transactions exceeding this limit should be optimized or restructured.

For transactions requiring more than 10M gas:

```javascript
// Split complex operations into multiple transactions
const operation1 = await contract.step1();
await operation1.wait();

const operation2 = await contract.step2();
await operation2.wait();
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/megaeth/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - MegaETH RPC Method

# eth_feeHistory - MegaETH RPC Method

Returns historical gas fee data on MegaETH, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on MegaETH without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on MegaETH.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Block Range Limit

On MegaETH, `eth_feeHistory` queries are subject to a **maximum block range of 10,000 blocks**. This means the `blockCount` parameter cannot exceed 10,000 blocks per request.

For querying larger block ranges, split your requests into batches:

```javascript
// Example: Query in 10,000-block batches
const MAX_RANGE = 10000;
const totalBlocks = 50000;
const newestBlock = await provider.getBlockNumber();

const allFeeHistory = [];

for (let i = 0; i < totalBlocks; i += MAX_RANGE) {
  const blockCount = Math.min(MAX_RANGE, totalBlocks - i);
  const feeHistory = await provider.send('eth_feeHistory', [
    blockCount,
    newestBlock - i,
    []
  ]);
  allFeeHistory.push(feeHistory);
}
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on MegaETH) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/megaeth/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/megaeth/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/megaeth/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/megaeth/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - MegaETH RPC Method

# eth_gasPrice - MegaETH RPC Method

Returns the current gas price on MegaETH in wei.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on MegaETH
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of MegaETH. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on MegaETH, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on MegaETH: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if MegaETH supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/megaeth/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/megaeth/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/megaeth/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - MegaETH RPC Method

# eth_getBalance - MegaETH RPC Method

Returns the balance of a given address on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getBalance` is fundamental for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on MegaETH
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to MegaETH
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on MegaETH. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} MegaETH`);
  return balance;
}

displayBalance('0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on MegaETH at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 MegaETH')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 MegaETH')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on MegaETH.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/megaeth/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/megaeth/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - MegaETH RPC Method

# eth_getBlockByHash - MegaETH RPC Method

Returns information about a block by hash on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getBlockByHash` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on MegaETH
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on MegaETH.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on MegaETH.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Full Block Restriction

On MegaETH, the `fullTransactionObjects` parameter is **disabled** for performance optimization. The method always returns transaction hashes instead of full transaction objects.

To get full transaction details, fetch them individually:

```javascript
// Get block with transaction hashes
const block = await provider.getBlock(blockHash, false);

// Fetch full transaction details as needed
for (const txHash of block.transactions) {
  const tx = await provider.getTransaction(txHash);
  console.log('Transaction:', tx);
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/megaeth/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - MegaETH RPC Method

# eth_getBlockByNumber - MegaETH RPC Method

Returns information about a block by block number on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getBlockByNumber` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on MegaETH
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on MegaETH with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on MegaETH. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Full Block Restriction

On MegaETH, the `fullTransactionObjects` parameter is **disabled** for performance optimization. The method always returns transaction hashes instead of full transaction objects.

To get full transaction details, fetch them individually:

```javascript
// Get block with transaction hashes
const block = await provider.getBlock('latest', false);

// Fetch full transaction details as needed
for (const txHash of block.transactions) {
  const tx = await provider.getTransaction(txHash);
  console.log('Transaction:', tx);
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/megaeth/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/megaeth/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - MegaETH RPC Method

# eth_getBlockReceipts - MegaETH RPC Method

Returns all transaction receipts for a block on MegaETH. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getBlockReceipts` is useful for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for MegaETH, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on MegaETH. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xe2ae73c07a531471127f7a4e814d7d1e8dbd3def6152c60e2e0284024798056e",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/megaeth/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/megaeth/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/megaeth/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - MegaETH RPC Method

# eth_getCode - MegaETH RPC Method

Returns the bytecode at a given address on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getCode` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on MegaETH
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on MegaETH:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on MegaETH:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/megaeth/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/megaeth/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - MegaETH RPC Method

# eth_getFilterChanges - MegaETH RPC Method

Polls a filter on MegaETH for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getFilterChanges` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on MegaETH
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on MegaETH:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/megaeth/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/megaeth/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/megaeth/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/megaeth/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/megaeth/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - MegaETH RPC Method

# eth_getFilterLogs - MegaETH RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on MegaETH. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getFilterLogs` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on MegaETH
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/megaeth/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/megaeth/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/megaeth/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/megaeth/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - MegaETH RPC Method

# eth_getLogs - MegaETH RPC Method

Returns an array of all logs matching a given filter object on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on MegaETH for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on MegaETH
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on MegaETH.

```javascript
const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if MegaETH enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on MegaETH, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "0x70f337",
    "toBlock": "0x70f341",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Query ERC20 Transfer events
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "0x70f337",
      "toBlock": "0x70f341",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for Transfer event
const ERC20_ABI = [
  "event Transfer(address indexed from, address indexed to, uint256 value)"
];

const tokenAddress = '0x4200000000000000000000000000000000000006';
const contract = new Contract(tokenAddress, ERC20_ABI, provider);

// Query Transfer events in block range
const fromBlock = 7402295; // 0x70f337
const toBlock = 7402305;   // 0x70f341

const filter = contract.filters.Transfer();
const logs = await contract.queryFilter(filter, fromBlock, toBlock);

console.log(`Found ${logs.length} Transfer events`);
logs.forEach(log => {
  console.log(`From: ${log.args.from}`);
  console.log(`To: ${log.args.to}`);
  console.log(`Amount: ${log.args.value.toString()}`);
});
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Query Transfer events
filter_params = {
    'fromBlock': 0x70f337,
    'toBlock': 0x70f341,
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}

logs = w3.eth.get_logs(filter_params)

print(f'Found {len(logs)} Transfer events')
for log in logs:
    # Decode Transfer event (from, to, value)
    from_address = '0x' + log['topics'][1].hex()[-40:]
    to_address = '0x' + log['topics'][2].hex()[-40:]
    value = int(log['data'].hex(), 16)
    
    print(f'From: {from_address}')
    print(f'To: {to_address}')
    print(f'Value: {value}')
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/megaeth/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/megaeth/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - MegaETH RPC Method

# eth_getStorageAt - MegaETH RPC Method

Returns the value from a storage position at a given address on MegaETH. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getStorageAt` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **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 high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **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": [
    "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "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-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', '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-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';

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-megaeth-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 = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
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-megaeth-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-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    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 MegaETH:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-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-megaeth-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 = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';
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 MegaETH:`);
  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/megaeth/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/megaeth/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/megaeth/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/megaeth/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - MegaETH RPC Method

# eth_getTransactionByHash - MegaETH RPC Method

Returns the information about a transaction by transaction hash on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getTransactionByHash` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on MegaETH
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on MegaETH. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on MegaETH. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/megaeth/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - MegaETH RPC Method

# eth_getTransactionCount - MegaETH RPC Method

Returns the number of transactions sent from an address on MegaETH, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getTransactionCount` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on MegaETH
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('MegaETH nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
nonce = get_transaction_count(address)
print(f'MegaETH nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("MegaETH nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on MegaETH:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/megaeth/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/megaeth/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/megaeth/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - MegaETH RPC Method

# eth_getTransactionReceipt - MegaETH RPC Method

Returns the receipt of a transaction by transaction hash on MegaETH. Receipt is only available for mined transactions.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_getTransactionReceipt` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on MegaETH and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on MegaETH. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on MegaETH, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/megaeth/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/megaeth/eth_getLogs) - Query logs by filter

---

## eth_hashrate - MegaETH RPC Method

# eth_hashrate - MegaETH RPC Method

Returns the legacy `eth_hashrate` compatibility value on MegaETH. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('MegaETH hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('MegaETH hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'MegaETH hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'MegaETH hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("MegaETH hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/megaeth/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/megaeth/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - MegaETH RPC Method

# eth_maxPriorityFeePerGas - MegaETH RPC Method

Returns the current suggested priority fee (tip) per gas in wei on MegaETH. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on MegaETH
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('MegaETH priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'MegaETH priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("MegaETH priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on MegaETH:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on MegaETH:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/megaeth/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/megaeth/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/megaeth/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/megaeth/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - MegaETH RPC Method

# eth_mining - MegaETH RPC Method

Checks the legacy `eth_mining` compatibility method on MegaETH. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('MegaETH mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('MegaETH mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'MegaETH mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'MegaETH mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("MegaETH mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/megaeth/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/megaeth/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - MegaETH RPC Method

# eth_newBlockFilter - MegaETH RPC Method

Creates a filter on MegaETH that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_newBlockFilter` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Block Monitoring** - Detect new blocks on MegaETH as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on MegaETH:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/megaeth/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/megaeth/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/megaeth/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - MegaETH RPC Method

# eth_newFilter - MegaETH RPC Method

Creates a filter object on MegaETH based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_newFilter` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Event Monitoring** - Subscribe to specific contract events on MegaETH such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on MegaETH:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/megaeth/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/megaeth/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/megaeth/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/megaeth/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/megaeth/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - MegaETH RPC Method

# eth_newPendingTransactionFilter - MegaETH RPC Method

Creates a filter on MegaETH that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on MegaETH to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on MegaETH...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on MegaETH:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/megaeth/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/megaeth/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/megaeth/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - MegaETH RPC Method

# eth_protocolVersion - MegaETH RPC Method

Returns the current Ethereum protocol version used by the MegaETH node.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_protocolVersion` is useful for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('MegaETH protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('MegaETH protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'MegaETH protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'MegaETH protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("MegaETH protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of MegaETH nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/megaeth/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/megaeth/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/megaeth/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - MegaETH RPC Method

# eth_sendRawTransaction - MegaETH RPC Method

Submits a pre-signed transaction for broadcast to MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to MegaETH
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the MegaETH mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/megaeth/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/megaeth/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/megaeth/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/megaeth/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - MegaETH RPC Method

# eth_sendTransaction - MegaETH RPC Method

Creates and sends a new transaction from an unlocked account on MegaETH. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for high-frequency DeFi developers, gaming studios, and teams building real-time applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('MegaETH tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('MegaETH tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'MegaETH tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'MegaETH tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("MegaETH tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on MegaETH dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/megaeth/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/megaeth/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - MegaETH RPC Method

# eth_signTransaction - MegaETH RPC Method

Signs a transaction with the private key of the specified account on MegaETH without submitting it to the network.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for high-frequency DeFi developers, gaming studios, and teams building real-time applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed MegaETH tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed MegaETH tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed MegaETH tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on MegaETH:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/megaeth/eth_accounts) - List accounts available for signing

---

## eth_syncing - MegaETH RPC Method

# eth_syncing - MegaETH RPC Method

Returns the sync status of your MegaETH node - either `false` when fully synced, or an object describing the sync progress.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_syncing` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('MegaETH node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('MegaETH node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("MegaETH node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/megaeth/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/megaeth/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/megaeth/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - MegaETH RPC Method

# eth_uninstallFilter - MegaETH RPC Method

Removes a filter on MegaETH that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`eth_uninstallFilter` is important for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/megaeth/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/megaeth/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/megaeth/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/megaeth/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/megaeth/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - MegaETH RPC Method

# net_listening - MegaETH RPC Method

Checks whether the connected MegaETH client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`net_listening` is useful for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('MegaETH node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'MegaETH node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("MegaETH node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/megaeth/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/megaeth/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/megaeth/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/megaeth/web3_clientVersion) - Get node client info

---

## net_peerCount - MegaETH RPC Method

# net_peerCount - MegaETH RPC Method

Returns the number of peers currently connected to your MegaETH node.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`net_peerCount` is important for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific MegaETH deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`MegaETH peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'MegaETH peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("MegaETH peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of MegaETH nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/megaeth/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/megaeth/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/megaeth/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/megaeth/web3_clientVersion) - Get node client info

---

## net_version - MegaETH RPC Method

# net_version - MegaETH RPC Method

Returns the current network ID on MegaETH as a decimal string. The network ID identifies which network the node is connected to.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`net_version` is essential for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Endpoint Identification** - Confirm your application is connected to the expected MegaETH network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('MegaETH network ID:', networkId);

// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'MegaETH network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("MegaETH network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/megaeth/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/megaeth/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/megaeth/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/megaeth/eth_syncing) - Check node sync progress

---

## trace_block - MegaETH RPC Method

# trace_block - MegaETH RPC Method

Returns traces for all transactions in a block on MegaETH.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on MegaETH
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in MegaETH chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/megaeth/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/megaeth/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/megaeth/trace_get) - Get a specific trace by index

---

## trace_call - MegaETH RPC Method

# trace_call - MegaETH RPC Method

Traces a call without creating a transaction on MegaETH, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on MegaETH
- **Pre-execution analysis** - Test contract interactions without spending gas for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f",
      "data": "0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f", "data": "0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
    data: '0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f',
        'data': '0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/megaeth/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/megaeth/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/megaeth/trace_transaction) - Trace a specific transaction

---

## trace_callMany - MegaETH RPC Method

# trace_callMany - MegaETH RPC Method

Traces multiple calls in sequence on MegaETH, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on MegaETH
- **Historical state comparison** - Compare how the same call would execute at different points in MegaETH chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f", "data": "0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"}, ["trace"]],
      [{"to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f", "data": "0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"}, ["trace"]],
        [{"to": "0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', data: '0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f' }, ['trace']],
    [{ to: '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', 'data': '0x70a082310000000000000000000000000E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'}, ['trace']],
        [{'to': '0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/megaeth/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/megaeth/eth_call) - Execute call without trace

---

## trace_filter - MegaETH RPC Method

# trace_filter - MegaETH RPC Method

Returns traces matching a filter on MegaETH.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on MegaETH
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x0E0f4Dd25ae8AB20E1583D9E8EDFf319A88e1d3f'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/megaeth/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/megaeth/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/megaeth/eth_getLogs) - Filter event logs

---

## trace_get - MegaETH RPC Method

# trace_get - MegaETH RPC Method

Returns a trace at a specific position within a transaction on MegaETH.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on MegaETH
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/megaeth/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/megaeth/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - MegaETH RPC Method

# trace_replayBlockTransactions - MegaETH RPC Method

Replays all transactions in a block on MegaETH and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on MegaETH
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in MegaETH chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/megaeth/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/megaeth/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/megaeth/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - MegaETH RPC Method

# trace_replayTransaction - MegaETH RPC Method

Replays a transaction on MegaETH and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on MegaETH
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/megaeth/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/megaeth/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/megaeth/trace_block) - Get all traces in a block

---

## trace_transaction - MegaETH RPC Method

# trace_transaction - MegaETH RPC Method

Returns all traces for a specific transaction on MegaETH.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for high-frequency trading, real-time gaming, instant payments, and latency-sensitive applications
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on MegaETH
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0xed92c2e964d7916f91fbc203f983bb89e15db600c1278d860812fe5c83b06692'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/megaeth/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/megaeth/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/megaeth/trace_filter) - Filter traces by criteria

---

## txpool_content - MegaETH RPC Method

# txpool_content - MegaETH RPC Method

Returns the full pending and queued transaction pool for the connected MegaETH endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`txpool_content` is useful for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/megaeth/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/megaeth/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/megaeth/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - MegaETH RPC Method

# txpool_status - MegaETH RPC Method

Returns transaction pool counters for the connected MegaETH endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`txpool_status` is valuable for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/megaeth/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/megaeth/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/megaeth/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - MegaETH RPC Method

# web3_clientVersion - MegaETH RPC Method

Returns the current client software version string for your MegaETH node, including the client name, version number, OS, and runtime.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

## When to Use This Method

`web3_clientVersion` is valuable for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('MegaETH client:', clientVersion);

// Using fetch
const response = await fetch('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'MegaETH client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("MegaETH client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/megaeth/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/megaeth/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/megaeth/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/megaeth/net_peerCount) - Get number of connected peers

---

## web3_sha3 - MegaETH RPC Method

# web3_sha3 - MegaETH RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on MegaETH.

> **Why MegaETH?** Build on the first real-time blockchain with sub-millisecond latency and 100,000+ TPS with sub-millisecond transaction streaming with 100,000+ sustained TPS and full EVM compatibility.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for high-frequency DeFi developers, gaming studios, and teams building real-time applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-megaeth-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/megaeth/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/megaeth/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/megaeth/web3_clientVersion) - Get node client version

---

## Monad - High-Performance EVM Layer 1 Documentation

# Monad - High-Performance EVM Layer 1 Documentation

## Monad RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Monad supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Monad?

Monad is a high-performance EVM Layer 1 blockchain designed to deliver exceptional throughput without sacrificing decentralization. Built from the ground up for speed and scalability:

### **Extreme Performance**

- **10,000+ TPS** - Handle massive transaction volumes with ease
- **1-second block times** - Near-instant finality for your users
- **Parallel execution** - Advanced transaction processing architecture

### **EVM Compatible**

- **Full Ethereum compatibility** - Deploy existing contracts without changes
- **Proven tooling** - Works with MetaMask, Hardhat, Foundry, and more
- **Familiar development** - Same APIs and libraries you already know

### **Growing Ecosystem**

- **Active community** - Rapidly expanding developer base
- **Testnet live** - Build and test today on the Monad testnet
- **Mainnet launched** - Production-ready network live since November 2025

## Quick Start with Monad

Connect to Monad in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Monad mainnet
const provider = new JsonRpcProvider(
  'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Monad mainnet
const web3 = new Web3(
  'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Monad:', chainId === 143);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { defineChain } from 'viem';

// Define Monad chain
const monad = defineChain({
  id: 143,
  name: 'Monad',
  network: 'monad',
  nativeCurrency: {
    decimals: 18,
    name: 'MON',
    symbol: 'MON',
  },
  rpcUrls: {
    default: {
      http: ['https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'],
    },
    public: {
      http: ['https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'],
    },
  },
});

// Create Monad client
const client = createPublicClient({
  chain: monad,
  transport: http(),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value    | Details      |
| ------------ | -------- | ------------ |
| Chain ID     | 143      | Mainnet      |
| Block Time   | 1 second | Average      |
| Gas Token    | MON      | Native token |
| RPC Standard | Ethereum | JSON-RPC 2.0 |

## API Reference

Monad supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/), plus additional methods for debugging, tracing, and transaction pool management.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  console.log('Transaction confirmed in block:', receipt.blockNumber);
  console.log('Gas used:', receipt.gasUsed.toString());

  return receipt;
}

// Monitor transaction status
const tx = await wallet.sendTransaction({
  to: recipient,
  value: amount,
});

console.log('Transaction sent:', tx.hash);
const receipt = await waitForTransaction(tx.hash);
```

### Gas Optimization

Optimize gas costs on Monad:

```javascript
// Estimate gas for a transaction
const gasEstimate = await provider.estimateGas({
  to: recipient,
  value: amount,
  data: '0x...',
});

console.log('Estimated gas:', gasEstimate.toString());

// Get current gas price
const gasPrice = await provider.getGasPrice();
console.log('Current gas price:', gasPrice.toString());

// Use EIP-1559 pricing
const feeData = await provider.getFeeData();
const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
};
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const currentBlock = await provider.getBlockNumber();
  const events = [];
  const batchSize = 5000; // Monad's high throughput supports larger batches

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

// Send batch request
const results = await Promise.all(
  batch.map(req => provider.send(req.method, req.params))
);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class MonadProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Monad-Specific Features

### Local Mempool Design

Monad does not have a global mempool. Each RPC node maintains its own local mempool, which affects transaction visibility:

```javascript
// Query transaction pool status by address
const statusByAddress = await provider.send('txpool_statusByAddress', [address]);
console.log('Pending transactions:', statusByAddress);

// Query transaction pool status by hash
const statusByHash = await provider.send('txpool_statusByHash', [txHash]);
console.log('Transaction status:', statusByHash);
```

### Transaction Pool Management

Use these Monad-specific methods for mempool operations:

```javascript
// Get pending transaction count for an address
const pendingCount = await provider.getTransactionCount(address, 'pending');
```

## Troubleshooting Common Issues

### Error: "Insufficient funds"

Ensure your account has enough MON for gas:

```javascript
// Check balance before sending transaction
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more MON`);
}
```

### Error: "Transaction underpriced"

Monad uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Monad requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Monad)
const provider = new JsonRpcProvider(
  'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Higher throughput and faster finality
// Note: Different chain ID (143)
// Note: Different native token (MON instead of ETH)
// Note: Local mempool design (no global mempool)
```

## Resources & Tools

### Official Resources

- [Monad Documentation](https://docs.monad.xyz)
- [Monad Explorer](https://monadexplorer.com)
- [Monad Testnet Explorer](https://testnet.monadexplorer.com)

### Developer Tools

- [Add Monad to MetaMask](https://docs.monad.xyz/guides/add-monad-to-wallet/mainnet)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Monad with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_getRawBlock

# debug_getRawBlock

Return the raw RLP-encoded bytes for a Monad block. This is a low-level debug method for tooling, protocol analysis, and serializer checks, not the decoded block structure most applications use day to day.

## Request Parameters

- `blockNumber` (`QUANTITY | TAG, required`): Hex block number or block tag such as latest.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawBlock",
  "params": ["0x3dd6abd"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Full block payload encoded as one RLP byte string.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xf952e2f90287a0950bf1eb8bdbddda0fdeed741074a0c9..."
}
```

## Error Responses

### Block not found

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Return Format

`debug_getRawBlock` accepts a block number and returns a single `0x`-prefixed RLP blob for that block. Use a fixed value such as `0x3dd6abd` when you need a reproducible debugging target instead of a moving `latest` response.

## Interpretation Guidance

The return value is the canonical RLP serialization of the full block, including the header and transaction body. Use it when you need to feed exact bytes into an RLP decoder, compare node implementations, or archive the raw block representation for later replay.

If you want a human-readable block, use [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) instead. `debug_getRawBlock` is better when the question is "what bytes did the node actually encode?" rather than "what fields are inside this block?"

## Caveats

- The payload is large and opaque by design. Expect long hex strings rather than structured JSON fields.
- This is RLP data, not a Substrate SCALE object, even though Monad has custom execution characteristics.
- Use exact block numbers when you need deterministic debugging sessions. `latest` is convenient, but it changes underneath you.

## Related Methods

- [`debug_getRawHeader`](https://www.dwellir.com/docs/monad/debug_getRawHeader) for just the block header bytes.
- [`debug_getRawReceipts`](https://www.dwellir.com/docs/monad/debug_getRawReceipts) for the raw receipt list tied to a block.
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) when you want the decoded JSON view of the same block.

---

## debug_getRawHeader

# debug_getRawHeader

Return the raw RLP-encoded block header for a Monad block. This is the narrowest way to inspect block metadata at the byte level without pulling the full transaction body.

## Request Parameters

- `blockNumber` (`QUANTITY | TAG, required`): Hex block number or block tag such as latest.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawHeader",
  "params": ["0x3dd6abd"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Block header encoded as one RLP byte string.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xf90287a0950bf1eb8bdbddda0fdeed741074a0c9c40ae7..."
}
```

## Error Responses

### Block not found

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Return Format

`debug_getRawHeader` accepts a block number and returns one header-sized RLP string for that block. Fixed block numbers such as `0x3dd6abd` are the right choice when you need byte-for-byte comparisons across environments.

## Why You Would Use It

`debug_getRawHeader` is the right tool when you care about the exact encoded header but not the transaction list. That comes up in header verification, proof tooling, light clients, and any workflow where you need to isolate consensus and block metadata from transaction payloads.

Compared with [`debug_getRawBlock`](https://www.dwellir.com/docs/monad/debug_getRawBlock), this method reduces payload size and keeps the debugging target focused. Compared with [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber), it preserves the original RLP bytes instead of giving you decoded JSON fields.

## Caveats

- The response is still opaque hex, so you need an RLP decoder to inspect individual header fields.
- Use a fixed block number for reproducible comparisons; the encoded header changes every block.
- This method is meant for infrastructure and protocol tooling, not for routine application reads.

## Related Methods

- [`debug_getRawBlock`](https://www.dwellir.com/docs/monad/debug_getRawBlock) for the full block payload.
- `chain_getHeader` if you need a decoded Substrate-style header view from another stack.
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) for a decoded EVM block response.

---

## debug_getRawReceipts

# debug_getRawReceipts

Return the raw RLP-encoded receipt list for every transaction in a Monad block. This is useful when you need the exact receipt bytes that the node generated instead of the decoded objects returned by `eth_getTransactionReceipt`.

## Request Parameters

- `blockNumber` (`QUANTITY | TAG, required`): Hex block number or block tag such as latest.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawReceipts",
  "params": ["0x3dd6abd"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): Array of RLP-encoded receipt blobs in transaction order.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0xf901c50180b9010000000000000000...",
    "0x02f90c090183200b20b90100000000..."
  ]
}
```

## Error Responses

### Block not found

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Return Format

`debug_getRawReceipts` accepts a block number and returns an array of raw receipt strings for the transactions in that block. Use a stable block such as `0x3dd6abd` when you need deterministic fixture data for decoder or archival work.

## Interpretation Guidance

Each array entry is one transaction receipt in raw RLP form, in the same order the transactions appear in the block. That makes this method valuable for decoder tests, receipt archival pipelines, and debugging situations where you want to compare raw receipt bytes across nodes or software versions.

If you only care about a single transaction outcome, [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) is usually simpler. Reach for `debug_getRawReceipts` when the whole block matters or when you need to preserve the serialized receipt data exactly as the node emitted it.

## Caveats

- Receipt arrays can be large on busy blocks, so avoid calling this method on hot paths in user-facing code.
- The response is raw RLP, not decoded logs and status fields.
- Pair the result with [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) when you need to line receipts up with specific transaction hashes.

## Related Methods

- [`debug_getRawBlock`](https://www.dwellir.com/docs/monad/debug_getRawBlock) for the raw block payload that the receipts belong to.
- [`debug_getRawTransaction`](https://www.dwellir.com/docs/monad/debug_getRawTransaction) for the raw signed transaction bytes.
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) for the decoded per-transaction receipt view.

---

## debug_getRawTransaction

# debug_getRawTransaction

Return the raw RLP-encoded bytes for a signed Monad transaction. Use it when you need the exact wire representation of a transaction rather than the decoded JSON fields.

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_getRawTransaction",
  "params": [
    "0x6a799a826eba52b79af941490b03af44673ea1849d4f36cef0637962f7419ccf"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Signed transaction payload encoded as one RLP byte string.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xf8908401db23758080940000000000000000000000000000000000001000..."
}
```

## Error Responses

### Transaction not found

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "transaction not found"
  }
}
```

## Return Format

`debug_getRawTransaction` accepts a transaction hash and returns a single RLP string for the signed transaction payload. A concrete hash such as `0x6a799a826eba52b79af941490b03af44673ea1849d4f36cef0637962f7419ccf` is useful when you need a stable example for replay or decoder tooling.

## What The Raw Bytes Give You

The returned hex string is the signed transaction payload exactly as the node stores and relays it. That is useful for debugging signing issues, testing RLP decoders, replaying a transaction in another environment, or comparing what different nodes believe the canonical signed payload should be.

Compared with [`eth_getTransactionByHash`](https://www.dwellir.com/docs/monad/eth_getTransactionByHash), this method does not decode fields for you. It preserves the original serialization, which is what you want when the bug is in encoding, signature recovery, or replay tooling.

## Caveats

- A successful response does not tell you whether the transaction succeeded on-chain; it only confirms the raw signed payload exists.
- For transaction status, pair this method with [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt).
- If the hash is unknown or pruned, expect a missing result rather than a decoded error object.

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/monad/eth_getTransactionByHash) for the decoded transaction fields.
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) for execution outcome and logs.
- [`debug_getRawBlock`](https://www.dwellir.com/docs/monad/debug_getRawBlock) when you need the full containing block in raw form.

---

## debug_traceBlock - Monad RPC Method

# debug_traceBlock - Monad RPC Method

Traces all transactions in a block on Monad by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Monad - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Monad
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Monad:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Monad blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/monad/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/monad/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/monad/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/monad/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Monad RPC Method

# debug_traceBlockByHash - Monad RPC Method

Traces all transactions in a block on Monad identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Monad - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Monad
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Monad:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Monad:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/monad/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/monad/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/monad/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/monad/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/monad/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Monad RPC Method

# debug_traceBlockByNumber - Monad RPC Method

Traces all transactions in a block on Monad identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Monad - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Monad execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Monad:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Monad:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/monad/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/monad/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/monad/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/monad/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Monad RPC Method

# debug_traceCall - Monad RPC Method

Traces a call on Monad without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Monad - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Monad
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "data": "0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
        "data": "0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
        "data": "0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    data: '0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    data: '0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    'data': '0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
        "data": "0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Monad to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Monad:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Monad:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/monad/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/monad/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/monad/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/monad/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Monad RPC Method

# debug_traceTransaction - Monad RPC Method

Traces a transaction execution on Monad by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Monad
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/monad/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/monad/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Monad RPC Method

# eth_accounts - Monad RPC Method

Returns a list of addresses owned by the client on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/monad/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/monad/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Monad RPC Method

# eth_blockNumber - Monad RPC Method

Returns the number of the most recent block on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_blockNumber` is fundamental for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Syncing Applications** - Keep your dApp in sync with the latest Monad blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Monad block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Monad block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Monad block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Monad block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Monad block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Monad:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Monad:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Monad node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/monad/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/monad/eth_syncing) - Check if node is still syncing

---

## eth_call - Monad RPC Method

# eth_call - Monad RPC Method

Executes a new message call immediately without creating a transaction on Monad. Used for reading smart contract state.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

The `eth_call` method serves these key scenarios for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Monad
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on high-throughput DeFi, latency-sensitive trading, and scalable EVM applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';
const walletAddress = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Monad. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Monad
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Monad

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "data": "0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "data": "0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    data := common.FromHex("0x70a082310000000000000000000000003bd359C1119dA7Da1D913D1C4D2B7c461115433A")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Monad RPC Method

# eth_chainId - Monad RPC Method

Returns the chain ID used for transaction signing on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_chainId` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on high-throughput DeFi, latency-sensitive trading, and scalable EVM applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/monad/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/monad/eth_syncing) - Check sync status

---

## eth_coinbase - Monad RPC Method

# eth_coinbase - Monad RPC Method

Checks the legacy `eth_coinbase` compatibility method on Monad. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Monad coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Monad coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Monad coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Monad coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Monad coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Monad nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/monad/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/monad/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/monad/eth_accounts) - List all accounts managed by the node

---

## eth_createAccessList

# eth_createAccessList

Creates an EIP-2930 access list that you can include in a transaction. This method can help optimize gas costs for complex transactions.

## Request

```json
{
  "jsonrpc": "2.0",
  "method": "eth_createAccessList",
  "params": [
    {
      "from": "0x...",
      "to": "0x...",
      "data": "0x..."
    },
    "latest"
  ],
  "id": 1
}
```

### Parameters

1. `Object` - Transaction call object:
   - `from` (optional): Address the transaction is sent from
   - `to`: Address the transaction is directed to
   - `gas` (optional): Integer of gas provided for the transaction execution
   - `gasPrice` (optional): Integer of gasPrice used for each paid gas
   - `value` (optional): Integer of value sent with this transaction
   - `data` (optional): Hash of the method signature and encoded parameters

2. `String|Number` - Block number, or the string "latest", "earliest" or "pending"

## Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "accessList": [
      {
        "address": "0x...",
        "storageKeys": [
          "0x..."
        ]
      }
    ],
    "gasUsed": "0x..."
  }
}
```

### Response Fields

- `accessList`: Array of address and storage key objects
- `gasUsed`: Estimated gas used with the access list

## Documentation

For more details, see the [Monad JSON-RPC documentation](https://docs.monad.xyz/reference/json-rpc).

---

## eth_estimateGas - Monad RPC Method

# eth_estimateGas - Monad RPC Method

Estimates the gas necessary to execute a transaction on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Monad
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Monad.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Monad may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/monad/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Monad RPC Method

# eth_feeHistory - Monad RPC Method

Returns historical gas fee data on Monad, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Monad without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Monad.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Monad) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/monad/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/monad/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Monad RPC Method

# eth_gasPrice - Monad RPC Method

Returns the current gas price on Monad in wei.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Monad
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Monad. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Monad, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Monad: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Monad supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/monad/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/monad/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Monad RPC Method

# eth_getBalance - Monad RPC Method

Returns the balance of a given address on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getBalance` is fundamental for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Monad
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Monad
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Monad. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Monad`);
  return balance;
}

displayBalance('0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Monad at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Monad')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Monad')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Monad.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/monad/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/monad/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Monad RPC Method

# eth_getBlockByHash - Monad RPC Method

Returns information about a block by hash on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getBlockByHash` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Monad
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Monad.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Monad.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/monad/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Monad RPC Method

# eth_getBlockByNumber - Monad RPC Method

Returns information about a block by block number on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getBlockByNumber` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Monad
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Monad with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Monad. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/monad/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/monad/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/monad/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Monad RPC Method

# eth_getBlockReceipts - Monad RPC Method

Returns all transaction receipts for a block on Monad. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getBlockReceipts` is useful for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Monad, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Monad. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xc627c6245574cee468cfccfd9cbfcb93c6d230d46a1b88f3363e0396cb8da145",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/monad/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Monad RPC Method

# eth_getCode - Monad RPC Method

Returns the bytecode at a given address on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getCode` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Monad
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on high-throughput DeFi, latency-sensitive trading, and scalable EVM applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Monad:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Monad:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/monad/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/monad/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Monad RPC Method

# eth_getFilterChanges - Monad RPC Method

Polls a filter on Monad for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getFilterChanges` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Monad
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Monad:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/monad/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/monad/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/monad/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/monad/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/monad/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Monad RPC Method

# eth_getFilterLogs - Monad RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Monad. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getFilterLogs` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Monad
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/monad/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/monad/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/monad/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/monad/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Monad RPC Method

# eth_getLogs - Monad RPC Method

Returns an array of all logs matching a given filter object on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Monad for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Monad
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Monad.

```javascript
const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Monad enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Monad, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/monad/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/monad/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Monad RPC Method

# eth_getStorageAt - Monad RPC Method

Returns the value from a storage position at a given address on Monad. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getStorageAt` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **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 high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **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": [
    "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "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-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A', '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-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';

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-monad-mainnet-full.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 = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
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-monad-mainnet-full.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-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    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 Monad:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.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-monad-mainnet-full.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 = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';
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 Monad:`);
  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/monad/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/monad/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/monad/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Monad RPC Method

# eth_getTransactionByHash - Monad RPC Method

Returns the information about a transaction by transaction hash on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getTransactionByHash` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Monad
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Monad. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Monad. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Monad RPC Method

# eth_getTransactionCount - Monad RPC Method

Returns the number of transactions sent from an address on Monad, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getTransactionCount` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Monad
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Monad nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A'
nonce = get_transaction_count(address)
print(f'Monad nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Monad nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Monad:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/monad/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/monad/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Monad RPC Method

# eth_getTransactionReceipt - Monad RPC Method

Returns the receipt of a transaction by transaction hash on Monad. Receipt is only available for mined transactions.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_getTransactionReceipt` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Monad and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Monad. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Monad, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc2d1de53ff3ce014bbe5d43a740e60a6cdb487a0ab4fda52deb11d0a0c5aa5c9")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/monad/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/monad/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Monad RPC Method

# eth_hashrate - Monad RPC Method

Returns the legacy `eth_hashrate` compatibility value on Monad. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Monad hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Monad hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Monad hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Monad hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Monad hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/monad/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/monad/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/monad/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Monad RPC Method

# eth_maxPriorityFeePerGas - Monad RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Monad. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Monad
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Monad priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Monad priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Monad priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Monad:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Monad:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/monad/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/monad/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/monad/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Monad RPC Method

# eth_mining - Monad RPC Method

Checks the legacy `eth_mining` compatibility method on Monad. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Monad mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Monad mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Monad mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Monad mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Monad mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/monad/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/monad/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/monad/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Monad RPC Method

# eth_newBlockFilter - Monad RPC Method

Creates a filter on Monad that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_newBlockFilter` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Block Monitoring** - Detect new blocks on Monad as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Monad:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/monad/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/monad/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/monad/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/monad/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Monad RPC Method

# eth_newFilter - Monad RPC Method

Creates a filter object on Monad based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_newFilter` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Event Monitoring** - Subscribe to specific contract events on Monad such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to high-throughput DeFi, latency-sensitive trading, and scalable EVM applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Monad:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/monad/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/monad/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/monad/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/monad/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/monad/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Monad RPC Method

# eth_newPendingTransactionFilter - Monad RPC Method

Creates a filter on Monad that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Mempool Monitoring** - Observe unconfirmed transactions on Monad to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for high-throughput DeFi, latency-sensitive trading, and scalable EVM applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Monad...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Monad:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/monad/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/monad/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/monad/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Monad RPC Method

# eth_protocolVersion - Monad RPC Method

Returns the current Ethereum protocol version used by the Monad node.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_protocolVersion` is useful for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Monad protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Monad protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Monad protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Monad protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Monad protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Monad nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/monad/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/monad/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/monad/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Monad RPC Method

# eth_sendRawTransaction - Monad RPC Method

Submits a pre-signed transaction for broadcast to Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Monad
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Monad mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/monad/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/monad/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/monad/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Monad RPC Method

# eth_sendTransaction - Monad RPC Method

Creates and sends a new transaction from an unlocked account on Monad. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Monad tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Monad tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Monad tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Monad tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Monad tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Monad dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/monad/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/monad/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Monad RPC Method

# eth_signTransaction - Monad RPC Method

Signs a transaction with the private key of the specified account on Monad without submitting it to the network.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Monad tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Monad tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Monad tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Monad:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/monad/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/monad/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/monad/eth_accounts) - List accounts available for signing

---

## eth_syncing - Monad RPC Method

# eth_syncing - Monad RPC Method

Returns the sync status of your Monad node - either `false` when fully synced, or an object describing the sync progress.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_syncing` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Monad node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Monad node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Monad node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/monad/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/monad/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/monad/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/monad/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Monad RPC Method

# eth_uninstallFilter - Monad RPC Method

Removes a filter on Monad that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`eth_uninstallFilter` is important for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/monad/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/monad/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/monad/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/monad/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/monad/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Monad RPC Method

# net_listening - Monad RPC Method

Checks whether the connected Monad client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`net_listening` is useful for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Monad node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Monad node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Monad node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/monad/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/monad/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/monad/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/monad/web3_clientVersion) - Get node client info

---

## net_peerCount - Monad RPC Method

# net_peerCount - Monad RPC Method

Returns the number of peers currently connected to your Monad node.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`net_peerCount` is important for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Monad deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Monad peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Monad peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Monad peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Monad nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/monad/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/monad/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/monad/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/monad/web3_clientVersion) - Get node client info

---

## net_version - Monad RPC Method

# net_version - Monad RPC Method

Returns the current network ID on Monad as a decimal string. The network ID identifies which network the node is connected to.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`net_version` is essential for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Endpoint Identification** - Confirm your application is connected to the expected Monad network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Monad network ID:', networkId);

// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Monad network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Monad network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/monad/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/monad/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/monad/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/monad/eth_syncing) - Check node sync progress

---

## web3_clientVersion - Monad RPC Method

# web3_clientVersion - Monad RPC Method

Returns the current client software version string for your Monad node, including the client name, version number, OS, and runtime.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

## When to Use This Method

`web3_clientVersion` is valuable for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Monad client:', clientVersion);

// Using fetch
const response = await fetch('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Monad client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Monad client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/monad/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/monad/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/monad/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/monad/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Monad RPC Method

# web3_sha3 - Monad RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Monad.

> **Why Monad?** Build on the parallel EVM L1 delivering 10,000 TPS with 400ms blocks and sub-cent gas fees with optimistic parallel execution, MonadBFT consensus, $244M Paradigm-led funding, and consumer-grade validator hardware requirements.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for high-performance dApp developers, DeFi builders, and teams requiring Ethereum compatibility at scale:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-monad-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/monad/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/monad/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/monad/web3_clientVersion) - Get node client version

---

## Movement Move REST API Guide

# Movement Move REST API Guide

## Movement RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Movement supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Movement

- Move-first execution environment with resource-oriented safety
- BlockSTM parallel execution for high throughput
- 1–3 second fast finality UX
- Compatibility with existing Aptos tooling and REST schemas

## Quick Start

### Endpoints

### SDK Installation

Aptos TS SDK
Movement CLI

```bash
npm i @aptos-labs/ts-sdk
```

```typescript
import { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: 'https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1'
});
const aptos = new Aptos(config);
const ledger = await aptos.getLedgerInfo();
console.log('Move chain ID:', ledger.chain_id);
```

```bash
# Example usage placeholder. Configure your CLI with the endpoint above
# API Base: https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1
```

## Network Information

| Parameter    | Value                                                        | Details               |
| ------------ | ------------------------------------------------------------ | --------------------- |
| API Base     | /v1                                                          | Aptos-compatible REST |
| Native Token | MOVE                                                         |                       |
| Finality     | \~1–3s                                                       | Fast confirmations    |
| Endpoint     | `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1` | Full REST base URL    |

## Move REST API Reference

Movement exposes Aptos-compatible REST APIs at `/v1` for MoveVM operations.

- [Accounts](https://www.dwellir.com/docs/movement/accounts)
- [Account Resources](https://www.dwellir.com/docs/movement/account_resources)
- [Account Modules](https://www.dwellir.com/docs/movement/account_modules)
- [Blocks](https://www.dwellir.com/docs/movement/blocks)
- [Transactions](https://www.dwellir.com/docs/movement/transactions)
- [Transaction Encode](https://www.dwellir.com/docs/movement/transaction_encode)
- [Transaction Simulate](https://www.dwellir.com/docs/movement/transaction_simulate)
- [Events](https://www.dwellir.com/docs/movement/events)
- [Tables](https://www.dwellir.com/docs/movement/tables)
- [Ledger](https://www.dwellir.com/docs/movement/ledger)
- [Health](https://www.dwellir.com/docs/movement/health)

## Movement-Specific Features

- [BlockSTM Parallel Execution](https://www.dwellir.com/docs/movement/blockstm)
- [Fast Finality Settlement](https://www.dwellir.com/docs/movement/fast_finality)
- [Shared Sequencer (M1)](https://www.dwellir.com/docs/movement/shared_sequencer)
- [MEV Protection](https://www.dwellir.com/docs/movement/mev_protection)

## Common Integration Patterns

- DEX or payments: leverage Move resources for precise asset accounting
- Data services: poll `/v1/blocks` and `/v1/transactions` for real-time indexing
- Custody/wallets: query account resources and event streams to reflect balances

## Performance Best Practices

- Design for BlockSTM: avoid write conflicts to maximize parallelism
- Gas optimization: use Move simulations to estimate gas under load
- Finality-aware UX: consider 1–3s finality in confirmations and polling intervals

## Migration Guides

- From Aptos: reuse Move modules with minimal changes; update REST base to Movement `/v1`
- From Sui: port object/resource models to Move on Movement; adjust package layout

## Troubleshooting

- Ensure correct address format (hex with `0x` prefix) and fully qualified module/function IDs
- Encode payloads with BCS and confirm signatures before submission
- Check `/v1/-/healthy` for node health and `/v1/ledger` for latest version

## Resources & Tools

- Move SDKs: Aptos TypeScript & Python SDKs
- [Movement Explorer](https://explorer.movementnetwork.xyz/)
- [Get your API key](https://dashboard.dwellir.com/register)

---

## Account Modules — Move REST API on Movement

# Account Modules — Move REST API on Movement

## Overview

The account modules endpoint lists all Move modules published under a specific on-chain account. Each module in the response includes its compiled bytecode and ABI (Application Binary Interface), which describes the module's structs, functions, and type parameters. This endpoint is essential for module discovery, ABI extraction, contract verification, and building developer tooling on Movement.

Movement uses the Aptos-compatible REST API format. If you have existing Aptos tooling, it works with Movement by changing the base URL to the Dwellir Movement endpoint.

> **Operational note:** On Dwellir shared Movement mainnet, account module listing depends on indexer-backed storage helpers. If the indexer reader is unavailable, this route can return `internal_error` instead of a module array.

## Endpoint

```
GET /v1/accounts/{address}/modules
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `address` (`string, required`): Path parameter: Hex-encoded account address (e.g., `0x1`). Must be `0x`-prefixed.
- `ledger_version` (`string, optional`): Query parameter: Ledger version to query. Defaults to the latest version. Use this to query historical module state.
- `start` (`string, optional`): Query parameter: Opaque pagination cursor from the previous response. Avoid hardcoding module names as cursors.
- `limit` (`integer, optional`): Query parameter: Maximum number of modules to return per request. Defaults to 25, maximum 1000.

## Request Example

```bash
# List all modules under the 0x1 framework account
    curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules" \
      -H "Accept: application/json" | jq '.[].abi.name'
```

## Response Fields

- `bytecode` (`string, required`): Hex-encoded compiled module bytecode
- `abi.address` (`string, required`): Address where the module is published
- `abi.name` (`string, required`): Module name
- `abi.friends` (`array, required`): Modules that have friend access
- `abi.exposed_functions` (`array, required`): Public and entry functions
- `abi.exposed_functions[].is_entry` (`boolean, required`): Whether the function can be called as a transaction entry point
- `abi.exposed_functions[].is_view` (`boolean, required`): Whether the function is a read-only view function
- `abi.structs` (`array, required`): Struct definitions with fields and abilities

## Successful Response

```json
[
  {
    "bytecode": "0xa11ceb0b060000000b01000e020e...",
    "abi": {
      "address": "0x1",
      "name": "coin",
      "friends": ["0x1::genesis", "0x1::aptos_coin"],
      "exposed_functions": [
        {
          "name": "balance",
          "visibility": "public",
          "is_entry": false,
          "is_view": true,
          "generic_type_params": [
            { "constraints": [] }
          ],
          "params": ["address"],
          "return": ["u64"]
        },
        {
          "name": "transfer",
          "visibility": "public",
          "is_entry": true,
          "is_view": false,
          "generic_type_params": [
            { "constraints": [] }
          ],
          "params": ["&signer", "address", "u64"],
          "return": []
        }
      ],
      "structs": [
        {
          "name": "CoinStore",
          "is_native": false,
          "abilities": ["key"],
          "generic_type_params": [
            { "constraints": [] }
          ],
          "fields": [
            { "name": "coin", "type": "0x1::coin::Coin<T0>" },
            { "name": "frozen", "type": "bool" }
          ]
        }
      ]
    }
  }
]
```

## Error Responses

### Error 1

- Description: Bad request

### Error 2

- Description: Account not found

### Error 3

- Description: Internal server error

## Code Examples

### Basic Module Listing

cURL
Python
TypeScript

```bash
# List all modules under the 0x1 framework account
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules" \
  -H "Accept: application/json" | jq '.[].abi.name'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# List all modules under 0x1
modules = client.account_modules("0x1")
for module in modules:
    print(f"Module: {module['abi']['name']}")
    for func in module["abi"]["exposed_functions"]:
        entry = " [entry]" if func["is_entry"] else ""
        view = " [view]" if func["is_view"] else ""
        print(f"  - {func['name']}{entry}{view}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const modules = await aptos.getAccountModules({ accountAddress: "0x1" });

for (const mod of modules) {
  console.log(`Module: ${mod.abi?.name}`);
  for (const func of mod.abi?.exposed_functions ?? []) {
    const tags = [
      func.is_entry ? "[entry]" : "",
      func.is_view ? "[view]" : "",
    ].filter(Boolean).join(" ");
    console.log(`  ${func.name} ${tags}`);
  }
}
```

### Paginated Module Retrieval

cURL
Python
TypeScript

```bash
# Fetch first page (5 modules)
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules?limit=5" \
  -H "Accept: application/json" | jq '.[].abi.name'

# Fetch the next page using the opaque cursor returned by your previous page
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/modules?limit=5&start=OPAQUE_CURSOR" \
  -H "Accept: application/json" | jq '.[].abi.name'
```

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
address = "0x1"
all_modules = []
start = None

while True:
    params = {"limit": 25}
    if start:
        params["start"] = start
    resp = requests.get(f"{BASE}/accounts/{address}/modules", params=params)
    page = resp.json()
    if not page:
        break
    all_modules.extend(page)
    start = page[-1]["abi"]["name"]

print(f"Total modules found: {len(all_modules)}")
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";
const address = "0x1";
const allModules: any[] = [];
let start: string | undefined;

while (true) {
  const params = new URLSearchParams({ limit: "25" });
  if (start) params.set("start", start);

  const resp = await fetch(
    `${BASE}/accounts/${address}/modules?${params}`
  );
  const page = await resp.json();
  if (!page.length) break;

  allModules.push(...page);
  start = page[page.length - 1].abi.name;
}

console.log(`Total modules: ${allModules.length}`);
```

### Extracting ABI for a Specific Module

cURL
Python
TypeScript

```bash
# Get a specific module by name (use the single-module endpoint)
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/module/coin" \
  -H "Accept: application/json" | jq '.abi.exposed_functions[] | {name, is_entry, is_view, params, return}'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Get a single module's ABI
module = client.account_module("0x1", "coin")
abi = module["abi"]

print(f"Module: {abi['name']}")
print(f"Structs: {[s['name'] for s in abi['structs']]}")
print(f"Entry functions: {[f['name'] for f in abi['exposed_functions'] if f['is_entry']]}")
print(f"View functions: {[f['name'] for f in abi['exposed_functions'] if f['is_view']]}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Fetch a single module by name
const module = await aptos.getAccountModule({
  accountAddress: "0x1",
  moduleName: "coin",
});

const entryFns = module.abi?.exposed_functions.filter((f) => f.is_entry) ?? [];
const viewFns = module.abi?.exposed_functions.filter((f) => f.is_view) ?? [];

console.log("Entry functions:", entryFns.map((f) => f.name));
console.log("View functions:", viewFns.map((f) => f.name));
console.log("Structs:", module.abi?.structs.map((s) => s.name));
```

## Common Use Cases

### Module Discovery

Enumerate all modules deployed by a protocol to understand its on-chain footprint. This is useful for auditors, indexers, and block explorers that need to catalog deployed contracts.

### ABI Extraction for Frontend Integration

Extract function signatures and parameter types to auto-generate TypeScript types or form-based UIs for interacting with Move modules. The ABI's `exposed_functions` array provides everything needed to build transaction payloads.

### Bytecode Verification

Compare on-chain bytecode against locally compiled bytecode to verify that a deployed module matches its published source code. This is a critical step in smart contract auditing.

### Historical State Analysis

Use the `ledger_version` parameter to query module state at specific historical points. This is useful for debugging deployments or tracking module upgrades over time.

## Movement-Specific Notes

- Module names on Movement follow the same conventions as Aptos: lowercase with underscores (e.g., `coin`, `managed_coin`, `aptos_coin`).
- The framework modules at `0x1` include the standard library, coin operations, and governance. These are the same as Aptos framework modules with Movement-specific extensions.
- Module bytecode can be large. When listing modules for accounts with many deployments, use pagination (`limit` and `start`) to avoid timeout issues.

## Related Endpoints

- [`GET /v1/accounts/{address}`](https://www.dwellir.com/docs/movement/accounts) -- Get basic account info including sequence number.
- [`GET /v1/accounts/{address}/module/{module_name}`](https://www.dwellir.com/docs/movement/modules_abi) -- Get a single module by name.
- [`GET /v1/accounts/{address}/resources`](https://www.dwellir.com/docs/movement/account_resources) -- List resources stored under an account.
- [`POST /v1/view`](https://www.dwellir.com/docs/movement/modules_view) -- Execute view functions from modules without a transaction.

---

## Account Resources — Move REST API

# Account Resources — Move REST API

## Overview

Lists all Move resources under an account. Useful for token balances and on-chain state.

## Endpoint

`GET /v1/accounts/{address}/resources`

## Movement-Specific Notes

- Resource types use canonical `0x...::module::Type` identifiers.

## Request

### Parameters

| Name    | Type   | Location | Required | Description         |
| ------- | ------ | -------- | -------- | ------------------- |
| address | string | path     | Yes      | Hex account address |

## Response

### Success Response (200)

```json
[
  {
    "type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
    "data": { "coin": { "value": "123" } }
  }
]
```

## Code Examples

cURL
Python
TypeScript

```bash
curl -X GET https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/resources \
  -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient
client = RestClient('https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1')
resources = client.account_resources('0x1')
print(resources)
```

```typescript
import { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';
const cfg = new AptosConfig({ network: Network.CUSTOM, fullnode: 'https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1' });
const aptos = new Aptos(cfg);
const resources = await aptos.getAccountResources({ accountAddress: '0x1' });
console.log(resources);
```

---

## Accounts — Move REST API on Movement

# Accounts — Move REST API on Movement

## Overview

The accounts endpoint returns core information about a Move account on Movement, including its sequence number (transaction nonce) and authentication key. This is the starting point for any account interaction: checking whether an account exists, reading its current nonce before submitting transactions, and verifying its authentication configuration.

Movement uses Aptos-compatible endpoints at `/v1`. Existing Aptos tooling and SDKs work with Movement by pointing the base URL to the Dwellir Movement endpoint.

## Endpoint

```
GET /v1/accounts/{address}
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `address` (`string, required`): Path parameter: Hex-encoded account address with `0x` prefix. Can be the full 32-byte address or shortened form (e.g., `0x1`).
- `ledger_version` (`string, optional`): Query parameter: Specific ledger version to query. Defaults to the latest version. Use this for historical account state.

## Request Example

```bash
# Get account info for the framework address
    curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1" \
      -H "Accept: application/json" | jq .

    # Response:
    # {
    #   "sequence_number": "0",
    #   "authentication_key": "0x0000000000000000000000000000000000000000000000000000000000000001"
    # }
```

## Response Fields

- `sequence_number` (`string, required`): The next expected transaction sequence number for this account. Acts as a nonce to prevent replay attacks. Starts at `"0"` for new accounts and increments by 1 with each committed transaction.
- `authentication_key` (`string, required`): The 32-byte hex-encoded authentication key that authorizes transactions from this account. Initially derived from the account's public key, but can be rotated independently of the address.

## Successful Response

```json
{
  "sequence_number": "42",
  "authentication_key": "0x5b4e9b38e5f63e3e8e1c8e9d7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8"
}
```

## Error Responses

### Error 1

- Description: Bad request

### Error 2

- Description: Account not found

### Error 3

- Description: Internal server error

## Code Examples

### Basic Account Query

cURL
Python
TypeScript

```bash
# Get account info for the framework address
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1" \
  -H "Accept: application/json" | jq .

# Response:
# {
#   "sequence_number": "0",
#   "authentication_key": "0x0000000000000000000000000000000000000000000000000000000000000001"
# }
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Get basic account info
info = client.account("0x1")
print(f"Sequence number: {info['sequence_number']}")
print(f"Authentication key: {info['authentication_key']}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const account = await aptos.getAccountInfo({ accountAddress: "0x1" });
console.log("Sequence number:", account.sequence_number);
console.log("Authentication key:", account.authentication_key);
```

### Get Sequence Number for Transaction Submission

cURL
Python
TypeScript

```bash
# Fetch current sequence number to use as nonce
ADDR="0xYOUR_ADDRESS"
SEQ=$(curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/$ADDR" \
  | jq -r '.sequence_number')
echo "Next sequence number to use: $SEQ"
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

address = "0xYOUR_ADDRESS"
info = client.account(address)
next_seq = int(info["sequence_number"])

print(f"Next sequence number: {next_seq}")

# Use this when building a transaction manually:
# transaction.sequence_number = next_seq
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const address = "0xYOUR_ADDRESS";
const account = await aptos.getAccountInfo({ accountAddress: address });
const nextSeq = BigInt(account.sequence_number);

console.log(`Next sequence number: ${nextSeq}`);

// The SDK handles sequence numbers automatically when using
// aptos.transaction.build.simple(), but manual control is useful
// for batch submissions.
```

### Check if an Account Exists

cURL
Python
TypeScript

```bash
# Check if an account exists (HTTP 200 = exists, 404 = does not exist)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0xSOME_ADDRESS")

if [ "$HTTP_CODE" = "200" ]; then
  echo "Account exists"
elif [ "$HTTP_CODE" = "404" ]; then
  echo "Account does not exist (never funded)"
else
  echo "Error: HTTP $HTTP_CODE"
fi
```

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
address = "0xSOME_ADDRESS"

resp = requests.get(f"{BASE}/accounts/{address}")
if resp.status_code == 200:
    print("Account exists")
    print(f"  Sequence number: {resp.json()['sequence_number']}")
elif resp.status_code == 404:
    print("Account does not exist (needs to be funded first)")
else:
    print(f"Error: {resp.status_code}")
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";
const address = "0xSOME_ADDRESS";

try {
  const resp = await fetch(`${BASE}/accounts/${address}`);
  if (resp.ok) {
    const data = await resp.json();
    console.log("Account exists, sequence:", data.sequence_number);
  } else if (resp.status === 404) {
    console.log("Account does not exist");
  }
} catch (err) {
  console.error("Network error:", err);
}
```

## Common Use Cases

### Transaction Nonce Management

Before submitting a transaction, query the account to get the current sequence number. This prevents nonce conflicts and replay attacks. For applications submitting many transactions, maintain a local nonce counter and resync with the chain periodically.

### Account Existence Checks

Before sending tokens to an address, verify the account exists. On Movement (like Aptos), accounts must be explicitly created by receiving an initial transfer or through the `create_account` function. Sending to a non-existent address will create the account automatically if using the `transfer` function from `0x1::aptos_account`.

### Authentication Key Monitoring

Track authentication key changes for security monitoring. If an account's authentication key changes unexpectedly, it may indicate a key rotation (legitimate) or compromise (security concern). Security dashboards and wallet applications should monitor this field.

## Movement-Specific Notes

- Use `0x`-prefixed addresses. The API accepts both full 32-byte addresses and shortened forms (e.g., `0x1` is equivalent to `0x0000...0001`).
- Move balances are tracked as on-chain resources, not as fields on the account object. To get token balances, query the account's resources for `0x1::coin::CoinStore<CoinType>`.
- Account creation on Movement requires an explicit on-chain action (funding or calling `create_account`). A valid key pair does not automatically create an account.
- The framework account `0x1` has a sequence number of `"0"` because it does not submit user transactions.

## Related Endpoints

- [`GET /v1/accounts/{address}/resources`](https://www.dwellir.com/docs/movement/account_resources) -- List all resources stored under an account (balances, NFTs, etc.).
- [`GET /v1/accounts/{address}/modules`](https://www.dwellir.com/docs/movement/account_modules) -- List all Move modules published by the account.
- [`POST /v1/transactions`](https://www.dwellir.com/docs/movement/transactions) -- Submit a transaction (uses the sequence number from this endpoint).
- [`GET /v1/accounts/{address}/events/{creation_number}`](https://www.dwellir.com/docs/movement/events) -- Query events emitted by the account.

---

## Blocks — Query Blocks (Move REST)

# Blocks — Query Blocks (Move REST)

## Overview

Fetch block data by height or by version.

## Endpoints

`GET /v1/blocks/by_height/{height}`

`GET /v1/blocks/by_version/{version}`

## Request

### Parameters

| Name    | Type   | Location | Required | Description    |
| ------- | ------ | -------- | -------- | -------------- |
| height  | string | path     | Yes      | Block height   |
| version | string | path     | Yes      | Ledger version |

## Response

### Success Response (200)

```json
{ "block_height": "0", "block_hash": "0x...", "first_version": "0" }
```

## Code Examples

cURL
Python
TypeScript

```bash
curl -X GET https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/blocks/by_height/0 -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient
client = RestClient('https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1')
block = client.block_by_height('0')
print(block)
```

```typescript
import { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';
const cfg = new AptosConfig({ network: Network.CUSTOM, fullnode: 'https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1' });
const aptos = new Aptos(cfg);
const block = await aptos.getBlockByHeight({ blockHeight: '0' });
console.log(block);
```

---

## BlockSTM — Parallel Execution on Movement

# BlockSTM — Parallel Execution on Movement

## Overview

BlockSTM is the parallel transaction execution engine at the heart of Movement's high-throughput architecture. Originally developed within the Aptos ecosystem, BlockSTM uses optimistic concurrency control to execute multiple transactions simultaneously while preserving deterministic, serial-equivalent results. This means Movement can process thousands of transactions per second without sacrificing correctness.

For developers building on Movement, BlockSTM is largely transparent. You write standard Move code and the runtime parallelizes execution automatically. However, understanding how BlockSTM works allows you to design contracts and transaction patterns that maximize throughput and minimize costly re-executions.

## How BlockSTM Works

BlockSTM operates on a simple but powerful principle: assume transactions do not conflict, execute them in parallel, then validate the assumption.

### The Execution Pipeline

1. **Optimistic execution** -- All transactions in a block are dispatched to worker threads simultaneously. Each transaction reads from a multi-version data structure that tracks writes from other transactions.

2. **Validation** -- After a transaction finishes executing, BlockSTM checks whether any value it read was subsequently written by a lower-indexed transaction (one that should have executed "before" it in serial order). If no conflicts are found, the result is committed.

3. **Re-execution on conflict** -- If a validation failure is detected (a read dependency was modified), the transaction is re-executed with the updated values. This process repeats until the transaction validates successfully.

4. **Commit** -- Once all transactions in the block have been validated, the final state is committed as if the transactions had executed sequentially.

### Multi-Version Data Structure

BlockSTM maintains a multi-version data store where each write is tagged with the index of the transaction that produced it. When a transaction reads a storage location, it sees the latest write from a lower-indexed transaction. This is the key mechanism that allows parallel execution to produce serial-equivalent results.

### Collaborative Scheduling

BlockSTM uses a collaborative scheduler that dynamically assigns execution and validation tasks to worker threads. Threads do not wait idly. If a transaction needs re-execution, the scheduler ensures dependent transactions are also re-validated, creating a wavefront of correct execution that propagates through the block.

## Performance Characteristics

BlockSTM performance scales with the degree of independence among transactions in a block. The two extremes are:

- **Fully independent transactions** (no shared state) -- Near-linear speedup with the number of cores. A block of 1,000 independent transfers can execute across 16 cores roughly 16 times faster than serial execution.

- **Fully dependent transactions** (every transaction reads the previous one's writes) -- Degrades to serial execution, since every transaction after the first must be re-executed once.

Real-world workloads fall between these extremes. Typical DeFi activity on Movement shows significant parallelism because different users interact with different accounts and resources.

### Throughput Expectations

| Workload type                    | Parallelism | Approximate speedup (16 cores) |
| -------------------------------- | ----------- | ------------------------------ |
| Independent token transfers      | Very high   | 10-16x                         |
| DEX swaps across different pools | High        | 6-12x                          |
| DEX swaps on the same pool       | Low         | 1-3x                           |
| Sequential state machine updates | None        | 1x (serial)                    |

The actual throughput you observe depends on the mix of transactions in each block and the number of execution cores available on Movement validators.

## Writing Parallel-Friendly Move Code

You do not need to add special annotations or parallel primitives to your Move code. BlockSTM parallelizes automatically. However, the way you structure your storage determines how much parallelism is possible.

### Principle: Minimize Write Conflicts

Two transactions conflict when one writes to a storage location that the other reads or writes. The fewer conflicts in a block, the more parallelism BlockSTM achieves.

**Conflict-prone pattern -- single global counter:**

```move
module 0xCAFE::counter {
    struct GlobalCounter has key {
        value: u64,
    }

    /// Every call writes to the same resource, serializing all transactions.
    public entry fun increment(account: &signer) acquires GlobalCounter {
        let counter = borrow_global_mut<GlobalCounter>(@0xCAFE);
        counter.value = counter.value + 1;
    }
}
```

Every invocation of `increment` reads and writes the same `GlobalCounter` resource. In a block with 100 calls to this function, BlockSTM must re-execute nearly every transaction, effectively running them serially.

**Parallel-friendly pattern -- per-user counters:**

```move
module 0xCAFE::counter_v2 {
    struct UserCounter has key {
        value: u64,
    }

    /// Each user writes to their own resource -- no conflicts across users.
    public entry fun increment(account: &signer) acquires UserCounter {
        let addr = signer::address_of(account);
        let counter = borrow_global_mut<UserCounter>(addr);
        counter.value = counter.value + 1;
    }
}
```

Because each user's counter lives at a different address, transactions from different users execute in parallel with zero conflicts.

### Principle: Batch Reads, Defer Writes

When your contract must access shared state, structure the logic so that reads happen early and writes happen late. This reduces the window in which conflicts can occur.

```move
module 0xCAFE::pool {
    /// Read pool state, compute locally, then write once.
    public entry fun swap(
        account: &signer,
        amount_in: u64,
    ) acquires Pool, UserBalance {
        // 1. Read shared pool state
        let pool = borrow_global<Pool>(@0xCAFE);
        let price = compute_price(pool, amount_in);

        // 2. Read user balance (per-user, no conflict with other users)
        let user_addr = signer::address_of(account);
        let balance = borrow_global_mut<UserBalance>(user_addr);

        // 3. Single write to shared state at the end
        let pool_mut = borrow_global_mut<Pool>(@0xCAFE);
        apply_swap(pool_mut, balance, amount_in, price);
    }
}
```

### Principle: Use Separate Resources for Independent Data

If a module tracks multiple independent pieces of data, store them in separate resources rather than a single struct. This way, transactions that only touch one piece of data do not conflict with transactions that touch another.

```move
module 0xCAFE::marketplace {
    /// Separate resources for separate concerns
    struct Listings has key { items: vector<Listing> }
    struct BidHistory has key { bids: vector<Bid> }
    struct FeeAccumulator has key { total: u64 }

    /// Adding a listing only touches Listings -- no conflict with bid queries.
    public entry fun add_listing(account: &signer, item: Listing) acquires Listings {
        let listings = borrow_global_mut<Listings>(signer::address_of(account));
        vector::push_back(&mut listings.items, item);
    }
}
```

## Comparison with Serial Execution

| Aspect           | Serial execution               | BlockSTM parallel execution                  |
| ---------------- | ------------------------------ | -------------------------------------------- |
| Throughput       | Limited by single-core speed   | Scales with available cores                  |
| Correctness      | Trivially correct (sequential) | Serial-equivalent via validation             |
| Developer effort | None                           | None (automatic), but storage design matters |
| Worst case       | Baseline                       | Same as serial (fully dependent workloads)   |
| Best case        | Baseline                       | Near-linear speedup                          |

Traditional EVM chains execute transactions strictly one after another. Even high-performance EVM chains that attempt parallel execution face challenges because Solidity's account model creates implicit dependencies through shared storage slots. Move's resource model, where data is stored at specific addresses with explicit ownership, naturally maps to BlockSTM's conflict detection, making parallelism more effective.

## Observability and Debugging

### Detecting Contention

When transactions in your application are frequently re-executed due to conflicts, you will observe:

- **Higher gas usage** than expected for the transaction complexity.
- **Increased latency** during high-traffic periods compared to low-traffic periods.
- **Simulation gas estimates that differ from on-chain gas** because simulation runs in isolation without contention.

### Load Testing for Parallelism

Use the transaction simulation endpoint to estimate gas costs under different conditions, then compare with on-chain execution during load tests.

```bash
# Simulate a batch of transactions to baseline gas costs
curl -X POST https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/simulate \
  -H "Content-Type: application/json" \
  -d '[{
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "0",
    "max_gas_amount": "10000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "9999999999",
    "payload": {
      "type": "entry_function_payload",
      "function": "0xCAFE::counter_v2::increment",
      "type_arguments": [],
      "arguments": []
    }
  }]'
```

### Monitoring in Production

Track these metrics to understand how BlockSTM is handling your workload:

- **Transaction gas used vs. simulated gas** -- A large gap suggests contention-induced re-execution.
- **Transaction success rate during traffic spikes** -- Contention does not cause failures, but it can cause transactions to exceed their `max_gas_amount` if re-execution burns extra gas.
- **Block inclusion time** -- Consistently slow inclusion may indicate your transactions are hitting hot storage locations.

## Best Practices Summary

1. **Prefer per-user resources** over global singletons for data that is written frequently.
2. **Separate read-heavy and write-heavy data** into distinct Move resources.
3. **Use events for coordination** instead of shared mutable state where possible. Events are append-only and do not create write conflicts.
4. **Test under realistic load** by simulating concurrent transactions that mirror expected production patterns.
5. **Design for the common case** -- optimize the most frequent transaction types for parallelism, even if rare administrative operations must serialize.

## Related Pages

- [Fast Finality Settlement](https://www.dwellir.com/docs/movement/fast_finality) -- How Movement's consensus delivers 1-3 second finality alongside parallel execution.
- [MEV Protection](https://www.dwellir.com/docs/movement/mev_protection) -- Transaction ordering fairness in Movement's parallel execution environment.
- [Transaction Simulation](https://www.dwellir.com/docs/movement/transaction_simulate) -- Simulate transactions to estimate gas and detect potential issues before submitting.
- [Transactions](https://www.dwellir.com/docs/movement/transactions) -- Submit and query transactions on the Movement REST API.

---

## Events — Move REST API on Movement

# Events — Move REST API on Movement

## Overview

Events on Movement are the primary mechanism for Move modules to emit observable, indexed data about on-chain actions. Every token transfer, swap, liquidity change, and governance vote produces events that off-chain applications can query. This endpoint lets you retrieve events by account address and creation number, with support for pagination and sequence filtering.

Events are append-only and immutable. Once emitted, an event cannot be modified or deleted, making the event log a reliable audit trail for on-chain activity.

> **Operational note:** On Dwellir shared Movement mainnet, this route depends on indexer-backed event readers. If the node returns `internal_error` because the indexer reader is unavailable, use the owning resource or an indexer-backed fallback as your source of truth.

## Endpoint

```
GET /v1/accounts/{address}/events/{creation_number}
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `address` (`string, required`): Path parameter: Account address that owns the event handle.
- `creation_number` (`string, required`): Path parameter: Creation number identifying the specific event handle. Each event handle registered under an account has a unique creation number.
- `start` (`string, optional`): Query parameter: Starting sequence number (inclusive). Use this for pagination or to resume from a known position. Defaults to `0`.
- `limit` (`integer, optional`): Query parameter: Maximum number of events to return. Defaults to 25, maximum 1000.

## Request Example

```bash
# Get the first 10 events from creation number 2 (deposit events)
    curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0xYOUR_ADDRESS/events/2?limit=10" \
      -H "Accept: application/json" | jq '.[] | {seq: .sequence_number, type: .type, data: .data}'
```

## Response Fields

- `version` (`string, required`): Ledger version (block height) when the event was emitted
- `guid.creation_number` (`string, required`): Creation number of the event handle
- `guid.account_address` (`string, required`): Account address owning the event handle
- `sequence_number` (`string, required`): Sequential index within this event handle (starts at 0)
- `type` (`string, required`): Fully qualified Move type of the event (e.g., `0x1::coin::DepositEvent`)
- `data` (`object, required`): Event payload. Structure depends on the event type.

## Successful Response

```json
[
  {
    "version": "125304892",
    "guid": {
      "creation_number": "2",
      "account_address": "0x1"
    },
    "sequence_number": "0",
    "type": "0x1::coin::DepositEvent",
    "data": {
      "amount": "100000000"
    }
  },
  {
    "version": "125405001",
    "guid": {
      "creation_number": "2",
      "account_address": "0x1"
    },
    "sequence_number": "1",
    "type": "0x1::coin::DepositEvent",
    "data": {
      "amount": "250000000"
    }
  }
]
```

## Error Responses

### Error 1

- Description: Bad request

### Error 2

- Description: Resource not found

### Error 3

- Description: Internal server error

## Understanding Event Handles

In Move, events are emitted through **event handles** stored as fields in account resources. Each event handle has:

- **Creation number** -- A unique identifier assigned when the event handle is created. This is what you pass in the URL path.
- **Sequence number** -- An auto-incrementing counter for events emitted through this handle. Starts at 0 and increases by 1 for each event.

For example, the `CoinStore` resource for a token contains two event handles:

- `deposit_events` -- Events emitted when tokens are deposited.
- `withdraw_events` -- Events emitted when tokens are withdrawn.

To find the creation number for a specific event handle, query the account's resources and look at the event handle fields.

## Code Examples

### Query Deposit Events

cURL
Python
TypeScript

```bash
# Get the first 10 events from creation number 2 (deposit events)
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0xYOUR_ADDRESS/events/2?limit=10" \
  -H "Accept: application/json" | jq '.[] | {seq: .sequence_number, type: .type, data: .data}'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Query deposit events (creation_number depends on the resource)
address = "0xYOUR_ADDRESS"
creation_number = 2  # deposit_events creation number

events = client.get_account_events(
    address,
    str(creation_number),
    start=0,
    limit=10,
)

for event in events:
    print(f"Seq #{event['sequence_number']}: {event['type']}")
    print(f"  Data: {event['data']}")
    print(f"  Ledger version: {event['version']}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Query events by creation number
const events = await aptos.getAccountEventsByCreationNumber({
  accountAddress: "0xYOUR_ADDRESS",
  creationNumber: 2, // deposit_events
});

for (const event of events) {
  console.log(`Event #${event.sequence_number}: ${event.type}`);
  console.log("  Data:", event.data);
}
```

### Paginated Event Streaming

cURL
Python
TypeScript

```bash
# Stream events in pages of 100
ADDRESS="0xYOUR_ADDRESS"
CREATION_NUM="2"
START=0
BASE="https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

while true; do
  EVENTS=$(curl -s "$BASE/accounts/$ADDRESS/events/$CREATION_NUM?start=$START&limit=100")
  COUNT=$(echo "$EVENTS" | jq 'length')

  if [ "$COUNT" = "0" ]; then
    echo "No more events. Total processed up to sequence: $START"
    break
  fi

  echo "Processing $COUNT events starting at sequence $START"
  echo "$EVENTS" | jq -c '.[] | {seq: .sequence_number, type: .type}'

  START=$((START + COUNT))
done
```

```python
import requests
import time

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
address = "0xYOUR_ADDRESS"
creation_number = 2
start = 0
page_size = 100

all_events = []
while True:
    resp = requests.get(
        f"{BASE}/accounts/{address}/events/{creation_number}",
        params={"start": start, "limit": page_size},
    )
    events = resp.json()

    if not events:
        break

    all_events.extend(events)
    print(f"Fetched {len(events)} events (total: {len(all_events)})")
    start += len(events)

print(f"Total events retrieved: {len(all_events)}")
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";
const address = "0xYOUR_ADDRESS";
const creationNumber = 2;
const pageSize = 100;
let start = 0;
const allEvents: any[] = [];

while (true) {
  const resp = await fetch(
    `${BASE}/accounts/${address}/events/${creationNumber}?start=${start}&limit=${pageSize}`
  );
  const events = await resp.json();

  if (!events.length) break;

  allEvents.push(...events);
  console.log(`Fetched ${events.length} events (total: ${allEvents.length})`);
  start += events.length;
}

console.log(`Total events: ${allEvents.length}`);
```

### Find Event Handle Creation Numbers

cURL
Python

```bash
# Find creation numbers by inspecting account resources
# Look for EventHandle fields in CoinStore resources
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0xYOUR_ADDRESS/resources" \
  -H "Accept: application/json" \
  | jq '.[] | select(.type | contains("CoinStore")) | {
      type: .type,
      deposit_events_creation: .data.deposit_events.guid.id.creation_num,
      withdraw_events_creation: .data.withdraw_events.guid.id.creation_num
    }'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

address = "0xYOUR_ADDRESS"
resources = client.account_resources(address)

for resource in resources:
    if "CoinStore" in resource["type"]:
        deposit_num = resource["data"]["deposit_events"]["guid"]["id"]["creation_num"]
        withdraw_num = resource["data"]["withdraw_events"]["guid"]["id"]["creation_num"]
        print(f"{resource['type']}:")
        print(f"  deposit_events creation_number: {deposit_num}")
        print(f"  withdraw_events creation_number: {withdraw_num}")
```

## Common Use Cases

### Token Transfer Monitoring

Track all deposits and withdrawals for an account by querying the `deposit_events` and `withdraw_events` handles on the `CoinStore` resource. This is the foundation for wallet transaction histories and accounting integrations.

### DeFi Activity Indexing

Index swap events, liquidity additions, and yield harvests from DeFi protocol modules. Each protocol defines custom event types with specific data structures. Use the event type field to filter and parse events from different protocols.

### Real-Time Event Polling

Build a polling loop that periodically checks for new events by tracking the last seen sequence number. With Movement's 1-3 second finality, polling every 2-3 seconds provides near real-time event visibility without overwhelming the RPC endpoint.

## Movement-Specific Notes

- Event handles are stored in account resources. To find the creation number for a specific event type, first query the account's resources and inspect the event handle fields.
- Events are guaranteed to be ordered by sequence number within a single event handle. Across different handles, use the `version` field to determine chronological order.
- The `type` field uses the fully qualified Move type path (e.g., `0x1::coin::DepositEvent`). Use this to filter events by type in your application logic.

## Related Endpoints

- [`GET /v1/accounts/{address}`](https://www.dwellir.com/docs/movement/accounts) -- Get basic account info.
- [`GET /v1/accounts/{address}/resources`](https://www.dwellir.com/docs/movement/account_resources) -- List resources that contain event handles.
- [`GET /v1/transactions/by_hash/{hash}`](https://www.dwellir.com/docs/movement/transactions) -- Get transaction details including emitted events.
- [`POST /v1/view`](https://www.dwellir.com/docs/movement/modules_view) -- Call view functions to read current state.

---

## Fast Finality Settlement (1-3s) on Movement

# Fast Finality Settlement (1-3s) on Movement

## Overview

Transactions on Movement finalize in 1-3 seconds, providing near real-time user experiences for decentralized applications. This fast finality is achieved through Movement's combination of BFT consensus, the M1 shared sequencer, and the Move VM's parallel execution engine. Once a transaction reaches finality, applications can treat it as settled on Movement's current network architecture without waiting through long confirmation windows.

For developers, fast finality simplifies application architecture. You can eliminate long polling intervals, reduce the complexity of pending-state management, and build multi-step workflows that complete in seconds rather than minutes.

## How It Works

Movement achieves fast finality through several architectural components working together:

**BFT Consensus** -- Movement uses a Byzantine Fault Tolerant consensus mechanism that reaches agreement across validators in a single round of communication. Unlike proof-of-work chains where finality is probabilistic (more confirmations = more confidence), Movement's BFT consensus provides deterministic finality. A transaction is either finalized or it is not.

**M1 Shared Sequencer** -- The shared sequencer pre-orders transactions deterministically before they enter the execution layer. This removes ordering ambiguity and allows the execution layer to process transactions without waiting for consensus on order.

**BlockSTM Parallel Execution** -- The Move VM executes transactions in parallel using BlockSTM, meaning the execution phase does not bottleneck the pipeline. Even large blocks finalize quickly because transactions run concurrently across multiple cores.

**Settlement Layers** -- Movement's network docs describe separate sequencing, execution, and settlement layers. For application UX, the important distinction is that transaction finality on Movement arrives in seconds, while any broader settlement or bridge-specific confirmation policy can be handled separately based on your risk model.

## Why It Matters

Fast finality transforms both user experience and application design:

- **User experience** -- Traditional blockchain delays (12-15 minutes on Ethereum L1, 1-5 minutes on most L2s) force users to wait anxiously while transactions confirm. With 1-3 second finality, applications provide feedback comparable to Web2 services.

- **Capital efficiency** -- Bridges, DEXs, and lending protocols can minimize the time assets remain locked, reducing capital requirements and improving yields.

- **State management** -- Developers can query definitive state within seconds of transaction submission, eliminating the need for complex pending-state tracking and optimistic UI patterns.

- **Multi-step workflows** -- Sequences of dependent transactions (approve, swap, stake) complete in under 10 seconds total rather than requiring minutes of waiting between steps.

## Developer Use Cases

### 1. High-Frequency Trading Platforms

Build DEX interfaces that support professional traders with near-instant order confirmation. Market makers can update quotes rapidly, and arbitrageurs can close loops efficiently without multi-block confirmation delays.

### 2. Gaming and NFT Marketplaces

Create responsive gaming experiences where in-game purchases, item trades, and battle outcomes finalize in real-time. NFT marketplaces can process listings and sales with immediate ownership transfer, matching Web2 marketplace responsiveness.

### 3. Payment Systems

Implement point-of-sale systems and payment processors that confirm transactions fast enough for retail environments. Merchants receive guaranteed settlement in seconds, making blockchain payments practical for everyday commerce.

### 4. Cross-Chain Bridges

Develop faster bridge protocols with reduced lockup periods. Quick finality on the Movement side means bridge operators can safely release assets on the destination chain sooner, improving both capital efficiency and user experience.

### 5. Social and Content Platforms

Build social applications where likes, posts, and tips finalize instantly. Users get the responsive feedback loops they expect from modern social platforms without sacrificing decentralization.

### 6. Automated DeFi Strategies

Implement complex DeFi strategies that execute multiple steps in rapid succession. Fast finality ensures each step completes before the next begins, reducing slippage and enabling more sophisticated algorithmic trading.

## Code Examples

### Polling for Transaction Finality

cURL
Python
TypeScript

```bash
# Submit a transaction and poll for finality
TX_HASH="0xabc123..."

# Poll every second (matches Movement's ~1-3s finality)
while true; do
  RESULT=$(curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_hash/$TX_HASH")
  SUCCESS=$(echo "$RESULT" | jq -r '.success // empty')
  if [ -n "$SUCCESS" ]; then
    echo "Transaction finalized: success=$SUCCESS"
    echo "$RESULT" | jq '.vm_status'
    break
  fi
  sleep 1
done
```

```python
import time
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# After submitting a transaction, wait for finality
tx_hash = "0xabc123..."

# Poll with short intervals -- finality is 1-3 seconds
for attempt in range(10):
    try:
        tx = client.wait_for_transaction(tx_hash)
        print(f"Transaction finalized: {tx}")
        break
    except Exception:
        time.sleep(1)
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// After submitting, wait for transaction finality
const txHash = "0xabc123...";

// The SDK's waitForTransaction polls with appropriate intervals
const result = await aptos.waitForTransaction({
  transactionHash: txHash,
  options: {
    timeoutSecs: 10, // Well beyond normal 1-3s finality
    checkSuccess: true,
  },
});

console.log("Transaction finalized:", result.success);
console.log("Gas used:", result.gas_used);
```

### Multi-Step Transaction Workflow

TypeScript
Python

```typescript
import { Aptos, AptosConfig, Network, Account } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

async function multiStepWorkflow(sender: Account) {
  // Step 1: Register coin store (~1-3s)
  const registerTx = await aptos.signAndSubmitTransaction({
    signer: sender,
    transaction: await aptos.transaction.build.simple({
      sender: sender.accountAddress,
      data: {
        function: "0x1::managed_coin::register",
        typeArguments: ["0xCAFE::token::USDC"],
        functionArguments: [],
      },
    }),
  });
  await aptos.waitForTransaction({ transactionHash: registerTx.hash });
  console.log("Step 1 complete: coin store registered");

  // Step 2: Transfer tokens (~1-3s, starts immediately after step 1)
  const transferTx = await aptos.signAndSubmitTransaction({
    signer: sender,
    transaction: await aptos.transaction.build.simple({
      sender: sender.accountAddress,
      data: {
        function: "0x1::coin::transfer",
        typeArguments: ["0x1::aptos_coin::AptosCoin"],
        functionArguments: ["0xRECIPIENT", "1000000"],
      },
    }),
  });
  await aptos.waitForTransaction({ transactionHash: transferTx.hash });
  console.log("Step 2 complete: tokens transferred");

  // Total time: ~4-6 seconds for both steps
}
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import TransactionPayload, EntryFunction

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

def multi_step_workflow(sender: Account):
    # Step 1: Register coin store (~1-3s finality)
    payload = EntryFunction.natural(
        "0x1::managed_coin",
        "register",
        ["0xCAFE::token::USDC"],
        [],
    )
    tx_hash = client.submit_transaction(sender, TransactionPayload(payload))
    client.wait_for_transaction(tx_hash)
    print("Step 1 complete: coin store registered")

    # Step 2: Transfer (~1-3s, starts immediately)
    payload = EntryFunction.natural(
        "0x1::coin",
        "transfer",
        ["0x1::aptos_coin::AptosCoin"],
        [b"\x00" * 32, (1000000).to_bytes(8, "little")],
    )
    tx_hash = client.submit_transaction(sender, TransactionPayload(payload))
    client.wait_for_transaction(tx_hash)
    print("Step 2 complete: tokens transferred")
```

## Best Practices

### Polling and State Management

Configure your application to poll every 1-2 seconds instead of the traditional 15-30 second intervals used on slower chains. Use exponential backoff starting at 500ms for the most responsive UX. WebSocket connections can provide even better real-time updates when supported by your RPC provider.

### Transaction Confirmation UX

Design confirmation flows that match the actual finality time. Show a brief loading state (1-3 seconds) rather than lengthy "this may take several minutes" warnings. Consider using optimistic UI updates with automatic rollback on the rare occasion a transaction fails.

### Error Handling

While finality is fast, network issues can still cause delays. Implement timeout handling at 10 seconds (well beyond normal finality time) and provide clear error messages. Include retry mechanisms with proper nonce management to handle transient failures gracefully.

### Multi-Step Workflows

Chain dependent transactions carefully. While you can submit the next transaction immediately after the previous finalizes, ensure your state queries have refreshed before building subsequent transactions that depend on updated state. Allow 100-200ms after finality for indexers to catch up.

## Performance Considerations

### Network Latency Impact

Your physical distance from Movement RPC nodes affects the perceived finality time. Users in regions far from node clusters may experience an additional 100-300ms of network latency. Consider using geographically distributed RPC endpoints to minimize this impact.

### Gas and Priority

During high network congestion, transactions with higher gas prices may finalize marginally faster. However, the difference is typically minimal compared to networks with longer block times. Monitor network congestion and adjust gas price recommendations accordingly.

### State Query Timing

After a transaction finalizes, allow 100-200ms for state to propagate through indexers and RPC nodes before querying dependent state. While the chain has finalized the transaction, some infrastructure may need a moment to update their cached views.

## Finality Comparison

| Chain          | Finality type           | Time to finality                     | Rollback risk              |
| -------------- | ----------------------- | ------------------------------------ | -------------------------- |
| Movement       | Deterministic (BFT)     | 1-3 seconds                          | None after finality        |
| Ethereum L1    | Probabilistic           | 12-15 minutes (safe)                 | Possible before finality   |
| Optimistic L2s | Optimistic              | 7 days (challenge period)            | During challenge window    |
| ZK Rollups     | Proof-based             | 10-30 minutes (proof generation)     | Before proof submission    |
| Solana         | Optimistic confirmation | \~400ms confirmation, \~12s finality | Possible during congestion |

Movement combines the speed of high-performance chains with the cryptographic finality guarantees of BFT consensus, making it particularly suitable for applications where both speed and certainty are critical.

## Related Pages

- [BlockSTM Parallel Execution](https://www.dwellir.com/docs/movement/blockstm) -- How Movement's execution engine processes transactions in parallel for high throughput.
- [MEV Protection](https://www.dwellir.com/docs/movement/mev_protection) -- Fair transaction ordering that complements fast finality.
- [Transactions](https://www.dwellir.com/docs/movement/transactions) -- Submit and query transactions on the Movement REST API.
- [Transaction Simulation](https://www.dwellir.com/docs/movement/transaction_simulate) -- Preview transaction effects before submitting.

---

## Health Check — Move REST API on Movement

# Health Check — Move REST API on Movement

## Overview

The health endpoint provides a lightweight way to verify that the Movement REST API service is running and responsive. Healthy responses return HTTP 200 with a short JSON body indicating node readiness. This endpoint is essential for monitoring, load balancer health probes, alerting systems, and pre-flight checks in your application startup logic.

On Dwellir Movement mainnet, the live path is `/-/healthy`. The older `/-/health` route currently returns `404`.

Unlike data-fetching endpoints, the health check is lightweight. In practice, poll every 5-10 seconds and add retry/backoff handling so shared-rate-limit keys stay resilient.

## Endpoint

```
GET /v1/-/healthy
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `duration_secs` (`integer, optional`): Optional Query parameter: If provided, the endpoint checks whether the node has received a new block within the specified number of seconds. If no block has been received in that window, it returns a non-200 status. Useful for detecting stale nodes.

## Request Example

```bash
# Simple health check -- returns HTTP status code
    curl -s -o /dev/null -w "%{http_code}" \
      "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy"
    # Output: 200

    # Health check with response body
    curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy"
    # Output: {"message":"aptos-node:ok"}

    # Check that node has received a block in the last 30 seconds
    curl -s -w "\nHTTP %{http_code}" \
      "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy?duration_secs=30"
```

## Response Fields

- `result` (`OBJECT, required`): ### Healthy Response (200) ``` {"message":"aptos-node:ok"} ``` The response body contains a short JSON message confirming the node is healthy. Most monitoring checks only require the `200` status code. ### Unhealthy / Stale Node Response (typically `503`) If `duration_secs` is provided and the node has not received a new block within that window: ```json { "message": "Node is not healthy. Last block received was more than 30 seconds ago.", "error_code": "node_not_healthy" } ``` ### Error Responses | Status | Description | Meaning | |---|---|---| | `200` | Healthy | Service is running and (if `duration_secs` was specified) has received a recent block | | `503` | Service unavailable | Service is running but stale or unhealthy | | `429` | Too Many Requests | Request volume is too high for the current key or tier | | Connection refused / timeout | Service down | Node process is not running or network is unreachable |

## Successful Response

```json
{
  "message": "Node is not healthy. Last block received was more than 30 seconds ago.",
  "error_code": "node_not_healthy"
}
```

## Error Responses

### Error 1

- Description: Healthy

### Error 2

- Description: Service unavailable

### Error 3

- Description: Service down

## Code Examples

### Basic Health Check

cURL
Python
TypeScript

```bash
# Simple health check -- returns HTTP status code
curl -s -o /dev/null -w "%{http_code}" \
  "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy"
# Output: 200

# Health check with response body
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy"
# Output: {"message":"aptos-node:ok"}

# Check that node has received a block in the last 30 seconds
curl -s -w "\nHTTP %{http_code}" \
  "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/-/healthy?duration_secs=30"
```

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

# Basic health check
resp = requests.get(f"{BASE}/-/healthy", timeout=5)
print(f"Status: {resp.status_code}")  # 200 = healthy
print(f"Body: {resp.text}")

# Check with freshness requirement (block within last 30 seconds)
resp = requests.get(f"{BASE}/-/healthy", params={"duration_secs": 30}, timeout=5)
if resp.status_code == 200:
    print("Node is healthy and synced")
else:
    print(f"Node may be stale: {resp.text}")
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";

// Basic health check
const resp = await fetch(`${BASE}/-/healthy`);
console.log(`Status: ${resp.status}`); // 200 = healthy
console.log(`Body: ${await resp.text()}`);

// Check with freshness requirement
const freshResp = await fetch(`${BASE}/-/healthy?duration_secs=30`);
if (freshResp.ok) {
  console.log("Node is healthy and synced");
} else {
  console.log("Node may be stale:", await freshResp.text());
}
```

### Continuous Monitoring Script

Python
TypeScript
Bash

```python
import requests
import time
from datetime import datetime

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
CHECK_INTERVAL = 10  # seconds
FRESHNESS_SECS = 30  # node must have a block within this window

consecutive_failures = 0

while True:
    try:
        start = time.time()
        resp = requests.get(
            f"{BASE}/-/healthy",
            params={"duration_secs": FRESHNESS_SECS},
            timeout=5,
        )
        latency_ms = (time.time() - start) * 1000

        if resp.status_code == 200:
            consecutive_failures = 0
            print(f"[{datetime.now()}] OK ({latency_ms:.0f}ms)")
        else:
            consecutive_failures += 1
            print(f"[{datetime.now()}] UNHEALTHY: {resp.status_code} ({latency_ms:.0f}ms)")
            if consecutive_failures >= 3:
                print("ALERT: 3 consecutive failures -- trigger notification")
                # send_alert("Movement node unhealthy")

    except requests.exceptions.Timeout:
        consecutive_failures += 1
        print(f"[{datetime.now()}] TIMEOUT")
    except requests.exceptions.ConnectionError:
        consecutive_failures += 1
        print(f"[{datetime.now()}] CONNECTION REFUSED")

    time.sleep(CHECK_INTERVAL)
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";
const CHECK_INTERVAL = 10_000; // 10 seconds
const FRESHNESS_SECS = 30;

let consecutiveFailures = 0;

async function checkHealth() {
  const start = Date.now();
  try {
    const resp = await fetch(
      `${BASE}/-/healthy?duration_secs=${FRESHNESS_SECS}`,
      { signal: AbortSignal.timeout(5000) }
    );
    const latency = Date.now() - start;

    if (resp.ok) {
      consecutiveFailures = 0;
      console.log(`[${new Date().toISOString()}] OK (${latency}ms)`);
    } else {
      consecutiveFailures++;
      console.log(`[${new Date().toISOString()}] UNHEALTHY: ${resp.status} (${latency}ms)`);
    }
  } catch (err) {
    consecutiveFailures++;
    console.log(`[${new Date().toISOString()}] ERROR: ${err}`);
  }

  if (consecutiveFailures >= 3) {
    console.log("ALERT: 3 consecutive failures");
  }
}

setInterval(checkHealth, CHECK_INTERVAL);
checkHealth(); // Run immediately on start
```

```bash
#!/usr/bin/env bash
# Simple health monitoring loop with alerting
BASE="https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
INTERVAL=10
FAILURES=0

while true; do
  HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
    --connect-timeout 5 --max-time 10 \
    "$BASE/-/healthy?duration_secs=30")

  TIMESTAMP=$(date -Iseconds)

  if [ "$HTTP_CODE" = "200" ]; then
    FAILURES=0
    echo "[$TIMESTAMP] OK"
  else
    FAILURES=$((FAILURES + 1))
    echo "[$TIMESTAMP] UNHEALTHY: HTTP $HTTP_CODE (failures: $FAILURES)"
    if [ "$FAILURES" -ge 3 ]; then
      echo "[$TIMESTAMP] ALERT: 3+ consecutive failures"
      # Add webhook/email notification here
    fi
  fi

  sleep $INTERVAL
done
```

### Application Startup Pre-Flight Check

Python
TypeScript

```python
import requests
import sys
import time

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

def wait_for_healthy_node(max_retries=5, retry_delay=3):
    """Block until the Movement node is healthy, or exit."""
    for attempt in range(max_retries):
        try:
            resp = requests.get(
                f"{BASE}/-/healthy",
                params={"duration_secs": 60},
                timeout=5,
            )
            if resp.status_code == 200:
                print(f"Movement node is healthy (attempt {attempt + 1})")
                return True
            print(f"Node unhealthy (attempt {attempt + 1}): {resp.status_code}")
        except Exception as e:
            print(f"Connection failed (attempt {attempt + 1}): {e}")
        time.sleep(retry_delay)

    print("ERROR: Movement node not available after retries. Exiting.")
    sys.exit(1)

# Call this at application startup before processing transactions
wait_for_healthy_node()
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";

async function waitForHealthyNode(maxRetries = 5, retryDelay = 3000) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const resp = await fetch(`${BASE}/-/healthy?duration_secs=60`, {
        signal: AbortSignal.timeout(5000),
      });
      if (resp.ok) {
        console.log(`Movement node is healthy (attempt ${attempt + 1})`);
        return;
      }
      console.log(`Node unhealthy (attempt ${attempt + 1}): ${resp.status}`);
    } catch (err) {
      console.log(`Connection failed (attempt ${attempt + 1}): ${err}`);
    }
    await new Promise((r) => setTimeout(r, retryDelay));
  }
  throw new Error("Movement node not available after retries");
}

// Call at application startup
await waitForHealthyNode();
```

## Common Use Cases

### Load Balancer Health Probes

Configure your load balancer (AWS ALB, nginx, HAProxy) to hit `/v1/-/healthy` every 5-10 seconds. Route traffic only to healthy backends. Use `duration_secs=30` to automatically remove stale nodes from rotation.

### CI/CD Deployment Verification

After deploying a new version of your application, run a health check against the Movement endpoint to verify connectivity. Fail the deployment pipeline if the node is unreachable.

### Multi-Endpoint Failover

If you use multiple RPC endpoints (primary and backup), check health before each request and failover to the backup if the primary is unhealthy. This pattern provides high availability for production applications.

## Integration Patterns

### Kubernetes Liveness/Readiness Probes

```yaml
# Example Kubernetes probe configuration for an app that depends on Movement
livenessProbe:
  httpGet:
    path: /internal/health  # Your app's health endpoint that checks Movement
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 15
readinessProbe:
  httpGet:
    path: /internal/ready   # Checks Movement node connectivity
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
```

### Prometheus Metrics

Expose health check results as Prometheus metrics for dashboarding and alerting:

```python
# Example: expose Movement health as a Prometheus gauge
from prometheus_client import Gauge
import requests

movement_health = Gauge("movement_node_healthy", "Movement node health status")
movement_latency = Gauge("movement_health_latency_ms", "Health check latency")

def update_metrics():
    try:
        start = time.time()
        resp = requests.get(f"{BASE}/-/healthy?duration_secs=30", timeout=5)
        movement_latency.set((time.time() - start) * 1000)
        movement_health.set(1 if resp.status_code == 200 else 0)
    except Exception:
        movement_health.set(0)
```

## Related Endpoints

- [`GET /v1`](https://www.dwellir.com/docs/movement/ledger) -- Get ledger information including current block height and chain ID.
- [`GET /v1/accounts/{address}`](https://www.dwellir.com/docs/movement/accounts) -- Query account information (a deeper connectivity test).
- [`POST /v1/transactions/simulate`](https://www.dwellir.com/docs/movement/transaction_simulate) -- Simulate a transaction (verifies full node functionality).

---

## Ledger — Chain Info (Move REST)

# Ledger — Chain Info (Move REST)

## Overview

Returns basic ledger information for the Move chain.

## Endpoint

`GET /v1`

## Movement-Specific Notes

- Use this to fetch `chain_id`, ledger version, and timestamps.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X GET https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1 \
  -H "Accept: application/json"
```

## Response Fields

- `chain_id` (`integer, required`): Numeric chain identifier for the connected Movement network
- `epoch` (`string, required`): Current epoch number
- `ledger_version` (`string, required`): Latest committed ledger version
- `oldest_ledger_version` (`string, required`): Oldest retained ledger version available for historical queries
- `ledger_timestamp` (`string, required`): Current ledger timestamp in microseconds
- `node_role` (`string, optional`): Node role reported by the REST service when exposed

## Successful Response

```json
{
  "chain_id": 126,
  "epoch": "6289",
  "ledger_version": "133153451",
  "oldest_ledger_version": "0",
  "ledger_timestamp": "1742302082746128",
  "node_role": "full_node"
}
```

## Code Examples

cURL
Python
TypeScript

```bash
curl -X GET https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1 -H "Accept: application/json"
```

```python
from aptos_sdk.client import RestClient
client = RestClient('https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1')
info = client.info()
print(info)
```

```typescript
import { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';
const cfg = new AptosConfig({ network: Network.CUSTOM, fullnode: 'https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1' });
const aptos = new Aptos(cfg);
const info = await aptos.getLedgerInfo();
console.log(info);
```

## Response Notes

The root ledger response is the canonical place to read chain identity, ledger version, oldest retained version, and timestamp fields on Movement's Aptos-compatible REST surface.

---

## MEV Protection on Movement

# MEV Protection on Movement

## Overview

Maximal Extractable Value (MEV) refers to the profit that validators, sequencers, or third parties can extract by reordering, inserting, or censoring transactions. On many blockchains, MEV costs users billions of dollars annually through frontrunning, sandwich attacks, and other predatory practices. Movement addresses MEV at the protocol level through its shared sequencer (M1) and the inherent safety properties of the Move VM, providing protection by default rather than requiring users to opt in.

## How It Works

### Shared Sequencer (M1) Fair Ordering

Movement's M1 shared sequencer implements MEV-aware ordering policies that prioritize fairness. When transactions arrive at the sequencer, they are ordered according to transparent rules rather than by the highest bidder or the most profitable arrangement for the sequencer.

Key mechanisms include:

- **Time-weighted ordering** -- Transactions are ordered primarily by arrival time, preventing validators from reordering them for profit.
- **Batch processing** -- Certain transaction types are processed in batches where all participants receive the same execution price, eliminating the advantage of being first.
- **Private transaction submission** -- Transactions can be submitted through private relays that shield them from public observation until inclusion in a block. This prevents the mempool observation that enables most MEV strategies.

### Move VM Language-Level Protections

The Move language provides structural protections that make certain MEV attacks harder to execute:

- **Resource-oriented model** -- Move's type system enforces that resources (tokens, assets) cannot be duplicated or implicitly destroyed. This eliminates certain classes of reentrancy-based MEV attacks.
- **Explicit capability system** -- Access to resources requires explicit capabilities, reducing the surface area for unauthorized access patterns that MEV bots exploit.
- **No dynamic dispatch** -- Move does not support arbitrary contract calls through dynamic dispatch, which limits the composability exploits that enable complex MEV strategies on EVM chains.

### Protection Against Common Attack Vectors

| Attack type            | How it works                                                                | Movement's protection                                                        |
| ---------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Frontrunning           | Attacker sees your pending transaction and submits the same trade first     | Private relay hides transactions; time-weighted ordering prevents reordering |
| Sandwich attack        | Attacker places buy before and sell after your swap to extract value        | Batch processing and private submission prevent observation and insertion    |
| Just-in-time liquidity | Attacker provides liquidity right before a large trade and removes it after | Fair ordering limits the precision of JIT timing                             |
| Time-bandit attacks    | Validator reorganizes recent blocks to capture MEV                          | BFT finality prevents block reorganization                                   |
| Censorship             | Validator excludes specific transactions                                    | Shared sequencer with inclusion guarantees                                   |

## Why It Matters

For end users, MEV protection means:

- **Better execution prices** on DEX swaps (no sandwich tax).
- **Fewer failed transactions** (no frontrunners pushing gas prices up).
- **Fair access** to NFT drops, token launches, and limited opportunities.

For developers, MEV protection means:

- **Simpler application design** -- No need to build custom MEV defenses into every contract.
- **New application categories** -- Sealed-bid auctions, fair token launches, and prediction markets become practical.
- **Better unit economics** -- More value stays with users and protocols rather than being extracted.

## Developer Use Cases

### 1. Decentralized Exchanges (DEXs)

Build DEX interfaces with natural slippage protection. Users receive execution prices closer to quoted prices without sandwich attacks inflating their costs. AMM pools can offer tighter spreads because less value leaks to MEV bots.

### 2. NFT Minting and Drops

Launch fair NFT drops where mint order is determined by MEV-resistant sequencing rather than gas wars. Dutch auctions and batch minting ensure collectors have equal access regardless of their technical sophistication.

### 3. Lending and Liquidation Systems

Design lending protocols where liquidations happen fairly. The predictable ordering ensures that liquidation incentives work as designed without excessive profits being extracted by MEV bots that frontrun legitimate liquidators.

### 4. Token Launch Platforms

Create token launch mechanisms with sealed-bid participation. Early buyers cannot be frontrun, and the opening price reflects genuine market demand rather than manipulation through strategic transaction ordering.

### 5. Prediction Markets

Build prediction markets where bet placement order does not leak information. Large bets cannot be frontrun, and market odds update fairly based on actual participation.

### 6. Cross-Chain Bridges

Develop bridge protocols that are not vulnerable to MEV attacks during cross-chain transfers. Protected ordering ensures fair exchange rates for users.

## Code Examples

### Submitting a Private Transaction

cURL
Python
TypeScript

```bash
# Standard transaction submission through Dwellir's endpoint
# Transactions submitted to the RPC are not broadcast to a public mempool
curl -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "42",
    "max_gas_amount": "10000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000000",
    "payload": {
      "type": "entry_function_payload",
      "function": "0xDEX::router::swap_exact_input",
      "type_arguments": [
        "0x1::aptos_coin::AptosCoin",
        "0xUSDC::coin::USDC"
      ],
      "arguments": ["1000000", "990000"]
    },
    "signature": {
      "type": "ed25519_signature",
      "public_key": "0xYOUR_PUBLIC_KEY",
      "signature": "0xYOUR_SIGNATURE"
    }
  }'
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import (
    EntryFunction,
    TransactionArgument,
    TransactionPayload,
)

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Transactions submitted through the SDK go directly to the sequencer
# without public mempool exposure
sender = Account.load_key("your_private_key_hex")

payload = EntryFunction.natural(
    "0xDEX::router",
    "swap_exact_input",
    ["0x1::aptos_coin::AptosCoin", "0xUSDC::coin::USDC"],
    [
        TransactionArgument(1000000, TransactionArgument.U64),
        TransactionArgument(990000, TransactionArgument.U64),  # min output (slippage)
    ],
)

tx_hash = client.submit_transaction(sender, TransactionPayload(payload))
client.wait_for_transaction(tx_hash)
print(f"Swap executed: {tx_hash}")
```

```typescript
import { Aptos, AptosConfig, Network, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Transactions go directly to the sequencer, bypassing public mempools
const sender = Account.fromPrivateKey({
  privateKey: new Ed25519PrivateKey("YOUR_PRIVATE_KEY"),
});

const transaction = await aptos.transaction.build.simple({
  sender: sender.accountAddress,
  data: {
    function: "0xDEX::router::swap_exact_input",
    typeArguments: [
      "0x1::aptos_coin::AptosCoin",
      "0xUSDC::coin::USDC",
    ],
    functionArguments: [
      "1000000",  // amount in
      "990000",   // minimum output (1% slippage tolerance)
    ],
  },
});

const result = await aptos.signAndSubmitTransaction({
  signer: sender,
  transaction,
});

await aptos.waitForTransaction({ transactionHash: result.hash });
console.log("Swap executed with MEV protection:", result.hash);
```

### Simulating Before Submitting (Slippage Check)

```bash
# Simulate a swap to check expected output before committing
curl -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/simulate" \
  -H "Content-Type: application/json" \
  -d '[{
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "42",
    "max_gas_amount": "10000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000000",
    "payload": {
      "type": "entry_function_payload",
      "function": "0xDEX::router::swap_exact_input",
      "type_arguments": [
        "0x1::aptos_coin::AptosCoin",
        "0xUSDC::coin::USDC"
      ],
      "arguments": ["1000000", "0"]
    },
    "signature": {
      "type": "ed25519_signature",
      "public_key": "0xYOUR_PUBLIC_KEY",
      "signature": "0x0000000000000000000000000000000000000000000000000000000000000000"
    }
  }]'
```

## Best Practices

### Set Appropriate Slippage Tolerances

Even with MEV protection, set reasonable slippage tolerances. The protection reduces but does not eliminate market impact from natural price movement. Use dynamic slippage calculation based on:

- Pool liquidity depth
- Recent price volatility
- Trade size relative to pool reserves

### Use Short Expiration Windows

Set transaction expiration timestamps close to the current time (30-60 seconds). This limits the window during which a transaction could be included under unfavorable conditions. Movement's fast finality means transactions that do not execute within a few seconds likely face issues that should be investigated rather than retried blindly.

### Batch Related Transactions Atomically

When executing multiple related operations (approve + swap, or multi-hop routes), consider whether they should be batched into a single atomic transaction. Atomic batching prevents partial execution and reduces the surface area for inter-transaction manipulation.

### Monitor Execution Quality

Track these metrics to verify MEV protection is working as expected:

- **Effective price vs. quoted price** at the time of submission.
- **Transaction revert rates** -- Unusual spikes may indicate manipulation attempts.
- **Execution delays** -- Transactions taking longer than 3 seconds consistently may warrant investigation.

## Performance Considerations

### Private Relay Latency

Private transaction submission may add 100-500ms of latency compared to direct mempool submission. For most use cases, this is a worthwhile tradeoff. Latency-critical applications should measure and optimize their relay selection.

### Gas Costs of Protection Patterns

Application-level protection mechanisms like commit-reveal schemes require multiple transactions. Calculate the break-even point where MEV protection value exceeds the additional gas costs -- typically around $100-500 in transaction value depending on network congestion.

### Ordering Guarantees

Movement's MEV protection provides strong but not absolute guarantees. Design applications with defense in depth, combining protocol-level protection with application-level safeguards like slippage limits and deadline enforcement.

## Advanced Techniques

### Sealed-Bid Mechanisms

Implement cryptographic commitment schemes where participants submit hashed bids that can only be revealed after the bidding window closes. Movement's fair ordering ensures reveals happen in an un-frontrunnable sequence.

### Time-Weighted Average Price (TWAP) Orders

Execute large trades across multiple blocks using TWAP algorithms. Movement's consistent ordering and MEV protection ensure each sub-transaction executes fairly without exploitation by MEV bots anticipating future parts of your order.

### Programmable Privacy

Use Move's capability system to create assets and operations with limited visibility. While the sequencer must order transactions, careful use of Move's type system can hide transaction details until execution.

## Comparison with Other Approaches

| Approach                          | Protection level                                 | User action required        | Scope                 |
| --------------------------------- | ------------------------------------------------ | --------------------------- | --------------------- |
| Movement (protocol-level)         | High -- sequencer + VM protections               | None (default)              | All transactions      |
| Flashbots Protect (Ethereum)      | Medium -- private relay only                     | Must opt in per transaction | Submission phase only |
| Ethereum PBS                      | Low -- democratizes MEV, does not eliminate it   | None                        | Block building only   |
| Solana (no mempool)               | Low -- validators can still reorder within slots | None                        | Partial               |
| Application-level (commit-reveal) | High for specific actions                        | Must use supporting dApps   | Per-application       |

Movement provides protocol-level MEV protection by default, meaning all users benefit without needing to understand MEV or take special precautions.

## Related Pages

- [Fast Finality Settlement](https://www.dwellir.com/docs/movement/fast_finality) -- Quick finality reduces the window for MEV extraction.
- [BlockSTM Parallel Execution](https://www.dwellir.com/docs/movement/blockstm) -- How parallel execution interacts with transaction ordering.
- [Shared Sequencer](https://www.dwellir.com/docs/movement/shared_sequencer) -- The M1 sequencer that enforces fair ordering.
- [Transaction Simulation](https://www.dwellir.com/docs/movement/transaction_simulate) -- Preview transaction outcomes before committing.

---

## Modules — ABI (Move REST)

# Modules — ABI (Move REST)

## Overview

Retrieve ABI for Move modules, including exposed functions and structs.

## Endpoint

`GET /v1/accounts/{address}/module/{module_name}`

## Movement-Specific Notes

- ABI helps construct view and entry function payloads.

## Request

### Parameters

| Name         | Type   | Location | Required | Description       |
| ------------ | ------ | -------- | -------- | ----------------- |
| address      | string | path     | Yes      | Publisher address |
| module\_name | string | path     | Yes      | Module name       |

## Response

### Success Response (200)

```json
{ "abi": { "name": "MyModule", "exposed_functions": [] } }
```

## Code Examples

cURL
TypeScript

```bash
curl -X GET https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/module/MyModule \
  -H "Accept: application/json"
```

```typescript
const res = await fetch('https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0x1/module/MyModule');
const json = await res.json();
console.log(json);
```

---

## View Functions — Move REST API on Movement

# View Functions — Move REST API on Movement

## Overview

View functions let you call read-only Move functions on-chain without submitting a transaction or paying gas. They are the primary way to query computed state from Move modules: token balances, pool prices, governance parameters, NFT metadata, and any other data exposed through `#[view]` functions. The response contains the return values of the function, serialized as JSON.

This is one of the most frequently used endpoints for dApp frontends and backend services that need to read on-chain state.

## Endpoint

```
POST /v1/view
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `ledger_version` (`string, optional`): Query parameter: Specific ledger version to execute against. Defaults to the latest version. Useful for querying historical state.
- `function` (`string, required`): Body Schema: Fully qualified function identifier: `{address}::{module}::{function_name}`
- `type_arguments` (`array of strings, required`): Body Schema: Generic type parameters. Pass `[]` if the function has no type parameters.
- `arguments` (`array, required`): Body Schema: Function arguments as JSON-encoded strings. Pass `[]` if the function takes no arguments.

## Request Example

```json
{
  "function": "0x1::coin::balance",
  "type_arguments": ["0x1::aptos_coin::AptosCoin"],
  "arguments": ["0xYOUR_ADDRESS"]
}
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (200) Returns an array of return values, JSON-encoded. The number of elements matches the number of return values in the Move function signature. ```json ["1000000"] ``` For functions that return multiple values: ```json ["1000000", "500000", true] ``` For functions that return structs: ```json [{ "coin": { "value": "1000000" }, "frozen": false }] ``` ### Error Responses | Status | Description | Common Cause | |---|---|---| | `400` | Bad request | Invalid function name, wrong number of arguments, type mismatch | | `404` | Module or function not found | Module does not exist at the specified address, or function is not a view function | | `500` | Internal server error / VM error | Function execution failed (e.g., abort in the Move code) | ```json { "message": "Function not found: 0x1::coin::nonexistent", "error_code": "function_not_found", "vm_error_code": null } ```

## Successful Response

```json
["1000000"]
```

## Code Examples

### Query Token Balance

cURL
Python
TypeScript

```bash
# Get MOVE token balance for an account
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view" \
  -H "Content-Type: application/json" \
  -d '{
    "function": "0x1::coin::balance",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0xYOUR_ADDRESS"]
  }'
# Response: ["1000000"] (in smallest unit, 8 decimals)
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Query MOVE token balance
result = client.view_function(
    "0x1::coin::balance",
    ["0x1::aptos_coin::AptosCoin"],
    ["0xYOUR_ADDRESS"],
)
balance = int(result[0])
print(f"Balance: {balance / 1e8:.8f} MOVE")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Query MOVE token balance
const [balance] = await aptos.view<[string]>({
  payload: {
    function: "0x1::coin::balance",
    typeArguments: ["0x1::aptos_coin::AptosCoin"],
    functionArguments: ["0xYOUR_ADDRESS"],
  },
});

console.log(`Balance: ${Number(balance) / 1e8} MOVE`);
```

### Get Chain ID

cURL
Python
TypeScript

```bash
# Get the chain ID (no arguments needed)
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view" \
  -H "Content-Type: application/json" \
  -d '{
    "function": "0x1::chain_id::get",
    "type_arguments": [],
    "arguments": []
  }'
# Response: [126]
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

result = client.view_function("0x1::chain_id::get", [], [])
chain_id = int(result[0])
print(f"Chain ID: {chain_id}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const [chainId] = await aptos.view<[string]>({
  payload: {
    function: "0x1::chain_id::get",
    typeArguments: [],
    functionArguments: [],
  },
});

console.log(`Chain ID: ${chainId}`);
```

### Query DEX Pool Price

cURL
Python
TypeScript

```bash
# Example: query a DEX pool's reserves (function signature varies by DEX)
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view" \
  -H "Content-Type: application/json" \
  -d '{
    "function": "0xDEX_ADDRESS::pool::get_reserves",
    "type_arguments": [
      "0x1::aptos_coin::AptosCoin",
      "0xUSDC_ADDRESS::coin::USDC"
    ],
    "arguments": []
  }'
# Response: ["50000000000", "125000000000"] (reserve_a, reserve_b)
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Query pool reserves (adjust function/address for your DEX)
result = client.view_function(
    "0xDEX_ADDRESS::pool::get_reserves",
    [
        "0x1::aptos_coin::AptosCoin",
        "0xUSDC_ADDRESS::coin::USDC",
    ],
    [],
)

reserve_a = int(result[0])
reserve_b = int(result[1])
price = reserve_b / reserve_a  # Simplified price calculation
print(f"Reserves: {reserve_a} / {reserve_b}")
print(f"Price: {price:.4f}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Query pool reserves
const [reserveA, reserveB] = await aptos.view<[string, string]>({
  payload: {
    function: "0xDEX_ADDRESS::pool::get_reserves",
    typeArguments: [
      "0x1::aptos_coin::AptosCoin",
      "0xUSDC_ADDRESS::coin::USDC",
    ],
    functionArguments: [],
  },
});

const price = Number(reserveB) / Number(reserveA);
console.log(`Reserves: ${reserveA} / ${reserveB}`);
console.log(`Price: ${price.toFixed(4)}`);
```

### Query Historical State

cURL
TypeScript

```bash
# Query balance at a specific ledger version (historical state)
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/view?ledger_version=100000000" \
  -H "Content-Type: application/json" \
  -d '{
    "function": "0x1::coin::balance",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0xYOUR_ADDRESS"]
  }'
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Query balance at a specific historical ledger version
const [historicalBalance] = await aptos.view<[string]>({
  payload: {
    function: "0x1::coin::balance",
    typeArguments: ["0x1::aptos_coin::AptosCoin"],
    functionArguments: ["0xYOUR_ADDRESS"],
  },
  options: {
    ledgerVersion: "100000000",
  },
});

console.log(`Historical balance: ${Number(historicalBalance) / 1e8} MOVE`);
```

## Common Use Cases

### DApp Frontend State Queries

View functions are the backbone of dApp frontends. Use them to display token balances, NFT ownership, pool prices, staking positions, and governance states without requiring the user to submit transactions.

### Price Oracles and Aggregators

Query multiple DEX pools to compute aggregated prices and find optimal swap routes. View functions are free and fast, making them ideal for real-time price feeds.

### Smart Contract Testing

Call view functions during development to verify your module's read-only functions return expected values. This is faster than submitting a full transaction for every state query during testing.

## Movement-Specific Notes

- The function identifier must be fully qualified: `{address}::{module}::{function_name}`. For framework functions, the address is `0x1`.
- Only functions marked with `#[view]` in the Move source can be called through this endpoint. Attempting to call a non-view function returns a 404 error.
- View function execution is free (no gas cost) but is still subject to computational limits. Extremely complex view functions may time out.
- All argument values must be passed as strings, even numeric types. The node handles deserialization.

## Related Endpoints

- [`GET /v1/accounts/{address}/modules`](https://www.dwellir.com/docs/movement/account_modules) -- List modules to discover available view functions.
- [`GET /v1/accounts/{address}/resources`](https://www.dwellir.com/docs/movement/account_resources) -- Read raw resource data (alternative to view functions for simple reads).
- [`POST /v1/transactions/simulate`](https://www.dwellir.com/docs/movement/transaction_simulate) -- Simulate a transaction to preview state changes (for write operations).
- [`POST /v1/tables/{handle}/item`](https://www.dwellir.com/docs/movement/tables) -- Query table data directly.

---

## Shared Sequencer (M1)

# Shared Sequencer (M1)

## Overview

Movement uses a decentralized shared sequencer (M1) for ordering with MEV-awareness. This improves fairness and reduces censorship risk.

## How It Works

The M1 shared sequencer is a decentralized network of nodes that collectively determine transaction ordering for Movement blockchain. Unlike traditional blockchains where individual validators or centralized sequencers control ordering, M1 uses a distributed consensus protocol to provide censorship-resistant, fair transaction sequencing. The sequencer network operates independently from block production, separating the concerns of ordering (handled by M1) from execution (handled by Movement validators).

M1 employs a sophisticated consensus mechanism that achieves Byzantine Fault Tolerance while maintaining high throughput. The sequencer nodes stake collateral and participate in a reputation system that incentivizes honest behavior. Transactions submitted to the network are batched and ordered according to transparent rules that prioritize fairness over pure profit extraction. The resulting transaction sequence is then committed to Movement's data availability layer, creating an immutable record of the canonical ordering.

This architecture provides atomic composability across different execution environments and rollups that use M1. Multiple chains can share the same sequencer, enabling seamless cross-chain interactions without traditional bridge delays. The sequencer's MEV-aware policies are implemented at the protocol level, meaning developers and users benefit automatically without needing special integrations.

The M1 network also implements slashing conditions for malicious behavior. Sequencer nodes that attempt to reorder transactions unfairly, censor valid transactions, or engage in other misbehavior risk losing their staked collateral. This economic security model ensures long-term reliability and trustworthiness of the sequencing layer.

## Why It Matters

Sequencer centralization has become a critical problem in the blockchain ecosystem. Most Layer 2 rollups rely on single, centrally-operated sequencers that represent single points of failure and censorship. If the sequencer goes offline, the entire chain stops processing transactions. If the sequencer operator acts maliciously, they can extract MEV, censor transactions, or manipulate ordering for profit.

Movement's shared sequencer approach solves these problems through decentralization while adding unique benefits. The censorship resistance ensures that valid transactions will always be included, making the system more credibly neutral. The shared aspect enables cross-chain atomic transactions and composability that's impossible with isolated sequencers. For developers, this means building applications that can interact seamlessly across different execution environments without complex bridge protocols.

The economic implications are significant. Shared sequencer fees are distributed among decentralized operators rather than accruing to a single entity, creating a more sustainable and equitable economic model. The MEV-aware policies ensure that the value created by the network flows to users and builders rather than being extracted by sophisticated arbitrageurs.

## Developer Use Cases

### 1. Cross-Chain DeFi Applications

Build DeFi protocols that execute atomic transactions across multiple chains sharing the M1 sequencer. Implement flash loans that work across execution environments, arbitrage strategies that don't require bridges, or liquidity pools that span multiple chains with instant rebalancing.

### 2. Decentralized Order Books

Create orderbook-based exchanges that leverage the shared sequencer for fair price-time priority matching. The decentralized ordering ensures no single party can manipulate order execution or extract unfair value from the matching process.

### 3. Multi-Chain Gaming Platforms

Design gaming experiences where assets and state exist across multiple chains but interact atomically through the shared sequencer. Players can execute complex in-game actions that span different execution environments without waiting for cross-chain bridges.

### 4. Fair Launch Platforms

Implement token launch mechanisms that use the sequencer's transparent ordering to ensure fair participation. The decentralized nature prevents the launch platform operator from favorably ordering their own transactions or those of privileged users.

### 5. Cross-Chain Governance Systems

Build DAO governance systems where proposals and votes can originate from multiple chains but are sequenced fairly. The shared sequencer ensures vote ordering is tamper-proof and that governance actions execute atomically across all participating chains.

### 6. Censorship-Resistant Applications

Develop applications that require strong censorship resistance guarantees, such as prediction markets, whistleblowing platforms, or free speech applications. The decentralized sequencer ensures that valid transactions cannot be censored by any single party.

## Notes for Builders

- **Submit txs through standard RPC**; sequencing is handled by M1.
- **MEV-aware ordering policies** aim to protect users and builders.

## Best Practices

### Transaction Submission Strategy

Submit transactions through any M1-compatible RPC endpoint - the decentralized network ensures consistent treatment regardless of your entry point. For latency-sensitive applications, connect to geographically proximate RPC nodes. Consider implementing fallback to multiple RPC providers to maintain uptime even if one provider experiences issues.

### Handling Sequencer Guarantees

Design your applications to leverage M1's ordering guarantees. Once a transaction receives a sequencing commitment, you can build subsequent logic that depends on that transaction's execution. This enables more complex multi-step workflows that would be risky with less reliable sequencing.

### Cross-Chain Interactions

When building cross-chain features, take advantage of M1's atomic composability. Structure your transactions to either fully succeed or fully revert across all participating chains. This eliminates the complex error handling required with traditional bridges where operations can succeed on one chain but fail on another.

### Monitoring Sequencer Health

Implement monitoring of M1 network health metrics. Track sequencer uptime, finality times, and any slashing events. While the decentralized nature provides resilience, monitoring helps you understand network conditions and adjust application behavior during unusual circumstances.

## Performance Considerations

### Sequencing Latency

The shared sequencer adds minimal latency to transaction processing - typically 100-300ms for sequencing commitment before execution begins. This is substantially faster than cross-chain bridges (minutes to hours) while providing stronger guarantees. For most applications, this tradeoff is extremely favorable.

### Network Congestion Handling

During high congestion, the sequencer prioritizes transactions using transparent rules based on fees and timing. Unlike centralized sequencers that might have opaque priority mechanisms, M1's rules are public and deterministic. Implement dynamic fee estimation that accounts for current network conditions.

### Cross-Chain Transaction Costs

Atomic cross-chain transactions incur sequencing fees from M1 plus execution fees on each participating chain. While more expensive than single-chain transactions, they're substantially cheaper and faster than achieving similar atomicity through traditional bridge protocols with their lock-and-mint mechanisms.

### Finality Guarantees

M1 provides probabilistic finality that strengthens over time as more sequencer nodes commit to the ordering. For critical operations, wait for sufficient sequencer confirmations (typically 2-3 seconds) before considering the order immutable. Less critical operations can proceed with single-node commitments.

## Comparison with Other Approaches

Centralized sequencers (used by most L2s like Optimism and Arbitrum) offer simplicity and low latency but suffer from single points of failure and censorship risks. Fully decentralized L1 consensus (like Ethereum) provides stronger decentralization but at the cost of throughput and latency. Solana's leader rotation provides some decentralization but with periods of centralized control during each validator's leader slot.

Movement's M1 shared sequencer strikes a balance: it's decentralized enough to resist censorship and single points of failure, yet efficient enough to provide sub-second sequencing commitments. The shared aspect is unique - while other chains have decentralized sequencers, M1's ability to sequence transactions across multiple execution environments enables entirely new categories of cross-chain applications.

Compared to cross-chain bridges, M1 provides faster, cheaper, and more secure cross-chain interaction. Traditional bridges require locking assets on the source chain, transmitting messages, and minting wrapped assets on the destination chain - a process that takes minutes to hours. M1 enables atomic execution across chains in seconds.

## Advanced Integration Patterns

### Atomic Cross-Chain Swaps

Implement trustless cross-chain swaps that leverage M1's atomic sequencing. Users can swap assets on different chains without requiring wrapped tokens, bridge operators, or long waiting periods. The sequencer ensures both legs of the swap execute together or not at all.

### Shared Liquidity Pools

Create liquidity pools that exist across multiple chains but operate as a single logical pool. The shared sequencer enables atomically updating pool state across all chains, preventing arbitrage opportunities that typically arise from fragmented liquidity.

### Multi-Chain Smart Contracts

Design smart contracts that call functions on contracts deployed to different chains. The shared sequencer ensures these cross-chain calls execute atomically, enabling complex application logic that spans multiple execution environments.

### Sequencer-Aware MEV Protection

Build MEV protection directly into your application logic by leveraging M1's transparent ordering rules. Submit bundles of transactions that should execute together, with the sequencer ensuring they maintain their relative ordering without interference from third-party MEV bots.

## Security Considerations

The shared sequencer's security derives from its Byzantine Fault Tolerant consensus and economic stake. As long as more than two-thirds of sequencer nodes by stake remain honest, the network provides correct ordering. The slashing mechanism ensures that attempting to manipulate ordering results in substantial financial loss, making attacks economically irrational for rational actors.

Applications should still implement defense-in-depth security. While M1 provides strong ordering guarantees, smart contract logic should validate all inputs and maintain invariants regardless of transaction ordering. The sequencer protects against ordering manipulation but doesn't prevent bugs in contract logic or attacks that don't rely on transaction ordering.

---

## Tables — Move REST API on Movement

# Tables — Move REST API on Movement

## Overview

Move tables are on-chain key-value stores used extensively by DeFi protocols, NFT collections, token registries, and governance systems on Movement. Unlike Move resources (which are stored at a specific account address), table items are stored under opaque handles and accessed by key. This endpoint lets you look up individual table items by providing the table handle, key type, value type, and key value.

Tables are the backbone of many Move data structures. Token balances in `CoinStore`, NFT ownership records, DEX liquidity positions, and staking delegations are all stored in tables.

## Endpoint

```
POST /v1/tables/{table_handle}/item
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `table_handle` (`string, required`): Path parameter: Hex-encoded table handle. Obtained from account resources that contain `Table` or `TableWithLength` fields.
- `ledger_version` (`string, optional`): Query parameter: Specific ledger version to query. Defaults to the latest version.
- `key_type` (`string, required`): Body Schema: Move type of the table key (e.g., `address`, `u64`, `0x1::string::String`).
- `value_type` (`string, required`): Body Schema: Move type of the table value.
- `key` (`any, required`): Body Schema: JSON-encoded key value matching `key_type`.

## Request Example

```json
{
  "key_type": "address",
  "value_type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
  "key": "0xYOUR_ADDRESS"
}
```

## Response Fields

- `result` (`OBJECT, required`): ### Success Response (200) The response body is the JSON-encoded value from the table. The structure depends on `value_type`. **Example: simple value** ```json "1000000" ``` **Example: struct value** ```json { "coin": { "value": "50000000000" }, "frozen": false, "deposit_events": { "counter": "15", "guid": { "id": { "creation_num": "2", "addr": "0xYOUR_ADDRESS" } } }, "withdraw_events": { "counter": "8", "guid": { "id": { "creation_num": "3", "addr": "0xYOUR_ADDRESS" } } } } ``` ### Error Responses | Status | Description | Common Cause | |---|---|---| | `400` | Bad request | Invalid key type, value type, or key encoding | | `404` | Table item not found | Key does not exist in the table | | `500` | Internal server error | Node issue, retry after a moment | ```json { "message": "Table item not found by Table handle(0x...), Table key(0x...)", "error_code": "table_item_not_found", "vm_error_code": null } ``` A `404` response is expected behavior when a key does not exist. Use this to check for existence (e.g., whether an address holds a specific token).

## Successful Response

```json
"1000000"
```

## Code Examples

### Look Up a Table Item

cURL
Python
TypeScript

```bash
# Look up a string-to-string table item
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/0xTABLE_HANDLE/item" \
  -H "Content-Type: application/json" \
  -d '{
    "key_type": "0x1::string::String",
    "value_type": "0x1::string::String",
    "key": "my_key"
  }'
```

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"
table_handle = "0xTABLE_HANDLE"

resp = requests.post(
    f"{BASE}/tables/{table_handle}/item",
    json={
        "key_type": "0x1::string::String",
        "value_type": "0x1::string::String",
        "key": "my_key",
    },
)

if resp.status_code == 200:
    print(f"Value: {resp.json()}")
elif resp.status_code == 404:
    print("Key not found in table")
else:
    print(f"Error: {resp.status_code} - {resp.text}")
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";
const tableHandle = "0xTABLE_HANDLE";

const resp = await fetch(`${BASE}/tables/${tableHandle}/item`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    key_type: "0x1::string::String",
    value_type: "0x1::string::String",
    key: "my_key",
  }),
});

if (resp.ok) {
  console.log("Value:", await resp.json());
} else if (resp.status === 404) {
  console.log("Key not found in table");
}
```

### Look Up Token Balance from a Table

cURL
Python
TypeScript

```bash
# Look up a token balance using address as key
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/0xBALANCE_TABLE_HANDLE/item" \
  -H "Content-Type: application/json" \
  -d '{
    "key_type": "address",
    "value_type": "u64",
    "key": "0xYOUR_ADDRESS"
  }'
# Response: "5000000000"
```

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

# Look up balance from a custom token's balance table
resp = requests.post(
    f"{BASE}/tables/0xBALANCE_TABLE_HANDLE/item",
    json={
        "key_type": "address",
        "value_type": "u64",
        "key": "0xYOUR_ADDRESS",
    },
)

if resp.status_code == 200:
    balance = int(resp.json())
    print(f"Balance: {balance}")
elif resp.status_code == 404:
    print("No balance entry (account has not interacted with this token)")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Use the SDK's table item lookup
const balance = await aptos.getTableItem<string>({
  handle: "0xBALANCE_TABLE_HANDLE",
  data: {
    key_type: "address",
    value_type: "u64",
    key: "0xYOUR_ADDRESS",
  },
});

console.log(`Balance: ${balance}`);
```

### Finding Table Handles from Resources

cURL
Python
TypeScript

```bash
# Step 1: Find table handles by inspecting account resources
# Tables appear as fields with "handle" properties in resource data
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/accounts/0xPROTOCOL_ADDRESS/resources" \
  -H "Accept: application/json" \
  | jq '.[] | select(.data.table? or (.data | keys[] | test("table";"i"))) | {type: .type, data: .data}'

# Step 2: Extract the handle value from the resource
# Example output might show: "balances": { "handle": "0xabc123...", "length": "42" }

# Step 3: Use the handle to look up items
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/tables/0xabc123/item" \
  -H "Content-Type: application/json" \
  -d '{"key_type": "address", "value_type": "u64", "key": "0xYOUR_ADDRESS"}'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

# Step 1: Get resources to find table handles
resources = client.account_resources("0xPROTOCOL_ADDRESS")

# Step 2: Find resources containing tables
for resource in resources:
    data = resource["data"]
    for key, value in data.items():
        if isinstance(value, dict) and "handle" in value:
            print(f"Found table '{key}' in {resource['type']}")
            print(f"  Handle: {value['handle']}")
            if "length" in value:
                print(f"  Length: {value['length']}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Find table handles in account resources
const resources = await aptos.getAccountResources({
  accountAddress: "0xPROTOCOL_ADDRESS",
});

for (const resource of resources) {
  const data = resource.data as Record<string, any>;
  for (const [key, value] of Object.entries(data)) {
    if (value && typeof value === "object" && "handle" in value) {
      console.log(`Table '${key}' in ${resource.type}`);
      console.log(`  Handle: ${value.handle}`);
    }
  }
}
```

### Checking if a Key Exists

Python
TypeScript

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

def table_key_exists(handle: str, key_type: str, value_type: str, key) -> bool:
    """Check if a key exists in a table. Returns True/False."""
    resp = requests.post(
        f"{BASE}/tables/{handle}/item",
        json={"key_type": key_type, "value_type": value_type, "key": key},
    )
    return resp.status_code == 200

# Example: check if an address is whitelisted
is_whitelisted = table_key_exists(
    "0xWHITELIST_TABLE_HANDLE",
    "address",
    "bool",
    "0xUSER_ADDRESS",
)
print(f"Whitelisted: {is_whitelisted}")
```

```typescript
const BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1";

async function tableKeyExists(
  handle: string,
  keyType: string,
  valueType: string,
  key: any
): Promise<boolean> {
  const resp = await fetch(`${BASE}/tables/${handle}/item`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ key_type: keyType, value_type: valueType, key }),
  });
  return resp.ok;
}

// Check if an address is whitelisted
const isWhitelisted = await tableKeyExists(
  "0xWHITELIST_TABLE_HANDLE",
  "address",
  "bool",
  "0xUSER_ADDRESS"
);
console.log(`Whitelisted: ${isWhitelisted}`);
```

## Common Use Cases

### Token Registry Lookups

Many token registries and metadata stores use tables. Look up token metadata (name, symbol, decimals, icon URL) by token address. This is common for wallet applications and DEX aggregators.

### NFT Ownership and Metadata

NFT collections use tables to map token IDs to owner addresses and metadata. Query individual token ownership, collection statistics, and property maps through table lookups.

### Protocol Configuration

DeFi protocols store configuration parameters (fee tiers, interest rates, oracle addresses) in tables. Query these to display current protocol parameters or validate settings before submitting transactions.

### Staking and Delegation Records

Staking protocols track delegations, rewards, and validator information in tables. Look up a user's staking position by their address, or query validator performance data.

## Movement-Specific Notes

- Table handles are opaque hex strings assigned when a table is created on-chain. They are not human-readable and cannot be derived -- you must discover them from the account resources that contain the table.
- Keys and values are BCS-encoded internally, but the REST API handles serialization and deserialization. You provide JSON-encoded values and receive JSON-encoded responses.
- There is no endpoint to enumerate all keys in a table. To iterate over table contents, you need an indexer or to use event logs that track insertions.
- Table lookups are constant-time operations (O(1)) on-chain, making them efficient for large data sets.

## Related Endpoints

- [`GET /v1/accounts/{address}/resources`](https://www.dwellir.com/docs/movement/account_resources) -- Find table handles within account resources.
- [`POST /v1/view`](https://www.dwellir.com/docs/movement/modules_view) -- Call view functions that may internally query tables.
- [`GET /v1/accounts/{address}/modules`](https://www.dwellir.com/docs/movement/account_modules) -- Inspect module ABIs to understand table key/value types.
- [`GET /v1/accounts/{address}/events/{creation_number}`](https://www.dwellir.com/docs/movement/events) -- Track table insertions and updates via events.

---

## Transaction Encode — Move REST API

# Transaction Encode — Move REST API

## Overview

Encodes transactions in BCS format for signing/submission.

## Endpoint

`POST /v1/transactions/encode_submission`

## Movement-Specific Notes

- Use correct function/module/type arguments for entry functions.

## Request

### Body Schema

```json
{ "sender": "0x...", "payload": { "type": "entry_function_payload", "function": "..." } }
```

## Response

### Success Response (200)

```json
"0x..." 
```

## Code Examples

cURL
Python
TypeScript

```bash
curl -X POST https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/encode_submission \
  -H "Content-Type: application/json" \
  -d '{"sender":"0x...","payload":{}}'
```

```python
# Build payload using aptos_sdk types and encode
```

```typescript
// SDK provides encode helpers for building payloads
```

---

## Transaction Simulation — Move REST API on Movement

# Transaction Simulation — Move REST API on Movement

## Overview

Transaction simulation lets you execute a transaction against the current on-chain state without actually committing it. The simulation returns the full execution result: whether the transaction would succeed, how much gas it would consume, what events it would emit, and what state changes it would produce. This is essential for gas estimation, error debugging, and pre-flight validation before spending real tokens.

Simulation does not submit a transaction to the chain, but the request still needs a structurally valid transaction envelope. In practice, that means the sender and authentication fields must line up with the payload you are simulating. SDK helpers usually build this envelope for you; if you hand-roll the REST request, treat a zero-filled signature as a placeholder rather than a guarantee that any sender will pass validation.

## Endpoint

```
POST /v1/transactions/simulate
```

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Request Parameters

- `estimate_gas_unit_price` (`boolean, optional`): Query parameter: If `true`, the node estimates a suitable gas unit price. Default: `false`.
- `estimate_max_gas_amount` (`boolean, optional`): Query parameter: If `true`, the node estimates the maximum gas amount. Default: `false`.
- `estimate_prioritized_gas_unit_price` (`boolean, optional`): Query parameter: If `true`, estimates a higher priority gas price. Default: `false`.

## Request Example

```json
{
  "sender": "0xYOUR_ADDRESS",
  "sequence_number": "42",
  "max_gas_amount": "100000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::coin::transfer",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0xRECIPIENT_ADDRESS", "1000000"]
  },
  "signature": {
    "type": "ed25519_signature",
    "public_key": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
```

## Response Fields

- `success` (`boolean, required`): Whether the simulated transaction would succeed
- `gas_used` (`string, required`): Estimated gas consumption
- `vm_status` (`string, required`): Human-readable execution status or error message
- `events` (`array, required`): Events that would be emitted
- `changes` (`array, required`): State changes that would be applied

## Successful Response

```json
[
  {
    "version": "125304892",
    "hash": "0x...",
    "state_change_hash": "0x...",
    "event_root_hash": "0x...",
    "state_checkpoint_hash": null,
    "gas_used": "542",
    "success": true,
    "vm_status": "Executed successfully",
    "accumulator_root_hash": "0x...",
    "changes": [
      {
        "address": "0xYOUR_ADDRESS",
        "state_key_hash": "0x...",
        "data": {
          "type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
          "data": { "coin": { "value": "899000000" } }
        },
        "type": "write_resource"
      },
      {
        "address": "0xRECIPIENT_ADDRESS",
        "state_key_hash": "0x...",
        "data": {
          "type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
          "data": { "coin": { "value": "1001000000" } }
        },
        "type": "write_resource"
      }
    ],
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "42",
    "max_gas_amount": "100000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000000",
    "payload": { "...": "..." },
    "events": [
      {
        "guid": { "creation_number": "3", "account_address": "0xYOUR_ADDRESS" },
        "sequence_number": "8",
        "type": "0x1::coin::WithdrawEvent",
        "data": { "amount": "1000000" }
      },
      {
        "guid": { "creation_number": "2", "account_address": "0xRECIPIENT_ADDRESS" },
        "sequence_number": "15",
        "type": "0x1::coin::DepositEvent",
        "data": { "amount": "1000000" }
      }
    ],
    "timestamp": "1699999950000000"
  }
]
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

### Error 5

### Error 6

### Error 7

## Code Examples

### Simulate a Token Transfer

cURL
Python
TypeScript

```bash
# Simulate a MOVE token transfer
# Placeholder signature; the node still validates the transaction envelope
curl -s -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/simulate" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "42",
    "max_gas_amount": "100000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "9999999999",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::coin::transfer",
      "type_arguments": ["0x1::aptos_coin::AptosCoin"],
      "arguments": ["0xRECIPIENT", "1000000"]
    },
    "signature": {
      "type": "ed25519_signature",
      "public_key": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "signature": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    }
  }' | jq '.[0] | {success, gas_used, vm_status}'

# Output: { "success": false, "gas_used": "0", "vm_status": "INVALID_AUTH_KEY" }
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import (
    EntryFunction,
    TransactionArgument,
    TransactionPayload,
)

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
sender = Account.load_key("YOUR_PRIVATE_KEY_HEX")

# Build payload
payload = EntryFunction.natural(
    "0x1::coin",
    "transfer",
    ["0x1::aptos_coin::AptosCoin"],
    [
        TransactionArgument(
            bytes.fromhex("RECIPIENT_ADDRESS"),
            TransactionArgument.ADDRESS,
        ),
        TransactionArgument(1_000_000, TransactionArgument.U64),
    ],
)

# Simulate (SDK handles the request envelope for you)
result = client.simulate_transaction(sender, TransactionPayload(payload))
sim = result[0]
print(f"Success: {sim['success']}")
print(f"Gas used: {sim['gas_used']}")
print(f"VM status: {sim['vm_status']}")

if sim["success"]:
    print(f"Events: {len(sim.get('events', []))}")
    for event in sim.get("events", []):
        print(f"  {event['type']}: {event['data']}")
```

```typescript
import { Aptos, AptosConfig, Network, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const sender = Account.fromPrivateKey({
  privateKey: new Ed25519PrivateKey("YOUR_PRIVATE_KEY"),
});

// Build the transaction
const transaction = await aptos.transaction.build.simple({
  sender: sender.accountAddress,
  data: {
    function: "0x1::coin::transfer",
    typeArguments: ["0x1::aptos_coin::AptosCoin"],
    functionArguments: ["0xRECIPIENT", "1000000"],
  },
});

// Simulate without committing
const [simulation] = await aptos.transaction.simulate.simple({
  signerPublicKey: sender.publicKey,
  transaction,
});

console.log(`Success: ${simulation.success}`);
console.log(`Gas used: ${simulation.gas_used}`);
console.log(`VM status: ${simulation.vm_status}`);
console.log(`Events: ${simulation.events?.length ?? 0}`);
```

### Gas Estimation with Auto-Estimate

cURL
Python
TypeScript

```bash
# Use estimate_gas_unit_price and estimate_max_gas_amount
# to let the node suggest optimal gas parameters
curl -s -X POST \
  "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/simulate?estimate_gas_unit_price=true&estimate_max_gas_amount=true" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "42",
    "max_gas_amount": "100000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "9999999999",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::coin::transfer",
      "type_arguments": ["0x1::aptos_coin::AptosCoin"],
      "arguments": ["0xRECIPIENT", "1000000"]
    },
    "signature": {
      "type": "ed25519_signature",
      "public_key": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "signature": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    }
  }' | jq '.[0] | {success, gas_used, max_gas_amount, gas_unit_price}'
```

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

# Simulate with gas estimation flags
resp = requests.post(
    f"{BASE}/transactions/simulate",
    params={
        "estimate_gas_unit_price": "true",
        "estimate_max_gas_amount": "true",
    },
    json={
        "sender": "0xYOUR_ADDRESS",
        "sequence_number": "42",
        "max_gas_amount": "100000",
        "gas_unit_price": "100",
        "expiration_timestamp_secs": "9999999999",
        "payload": {
            "type": "entry_function_payload",
            "function": "0x1::coin::transfer",
            "type_arguments": ["0x1::aptos_coin::AptosCoin"],
            "arguments": ["0xRECIPIENT", "1000000"],
        },
        "signature": {
            "type": "ed25519_signature",
            "public_key": "0x" + "00" * 32,
            "signature": "0x" + "00" * 64,
        },
    },
)

sim = resp.json()[0]
print(f"Estimated gas used: {sim['gas_used']}")
print(f"Suggested max_gas_amount: {sim['max_gas_amount']}")
print(f"Suggested gas_unit_price: {sim['gas_unit_price']}")

# Add a 20% buffer for safety
safe_max_gas = int(int(sim["gas_used"]) * 1.2)
print(f"Recommended max_gas_amount (with buffer): {safe_max_gas}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Use the SDK to estimate gas
const gasEstimate = await aptos.getGasPriceEstimation();
console.log(`Current gas price estimate: ${gasEstimate.gas_estimate}`);
console.log(`Prioritized estimate: ${gasEstimate.prioritized_gas_estimate}`);
```

### Debug a Failing Transaction

Python
TypeScript

```python
import requests

BASE = "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1"

def debug_transaction(sender, payload):
    """Simulate a transaction and print detailed debug information."""
    # First, get the current sequence number
    account = requests.get(f"{BASE}/accounts/{sender}").json()
    seq_num = account["sequence_number"]

    resp = requests.post(
        f"{BASE}/transactions/simulate",
        json={
            "sender": sender,
            "sequence_number": seq_num,
            "max_gas_amount": "1000000",  # Set high for debugging
            "gas_unit_price": "100",
            "expiration_timestamp_secs": "9999999999",
            "payload": payload,
            "signature": {
                "type": "ed25519_signature",
                "public_key": "0x" + "00" * 32,
                "signature": "0x" + "00" * 64,
            },
        },
    )

    sim = resp.json()[0]

    print("=== Simulation Result ===")
    print(f"Success: {sim['success']}")
    print(f"VM Status: {sim['vm_status']}")
    print(f"Gas Used: {sim['gas_used']}")

    if not sim["success"]:
        print("\n=== Error Analysis ===")
        vm_status = sim["vm_status"]
        if "EINSUFFICIENT_BALANCE" in vm_status:
            print("Cause: Sender does not have enough tokens for this operation")
        elif "EACCOUNT_NOT_FOUND" in vm_status:
            print("Cause: Target account does not exist on chain")
        elif "ECOIN_STORE_NOT_PUBLISHED" in vm_status:
            print("Cause: Recipient has not registered a CoinStore for this token")
        elif "ESEQUENCE_NUMBER" in vm_status:
            print("Cause: Incorrect sequence number")
        else:
            print(f"VM error: {vm_status}")
    else:
        print(f"\nEvents emitted: {len(sim.get('events', []))}")
        print(f"State changes: {len(sim.get('changes', []))}")

# Example: debug a transfer
debug_transaction("0xYOUR_ADDRESS", {
    "type": "entry_function_payload",
    "function": "0x1::coin::transfer",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0xRECIPIENT", "999999999999"],  # Possibly too much
})
```

```typescript
import { Aptos, AptosConfig, Network, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

async function debugTransaction(
  sender: Account,
  functionName: string,
  typeArgs: string[],
  args: string[]
) {
  const transaction = await aptos.transaction.build.simple({
    sender: sender.accountAddress,
    data: {
      function: functionName as `${string}::${string}::${string}`,
      typeArguments: typeArgs,
      functionArguments: args,
    },
  });

  const [simulation] = await aptos.transaction.simulate.simple({
    signerPublicKey: sender.publicKey,
    transaction,
  });

  console.log("=== Simulation Result ===");
  console.log(`Success: ${simulation.success}`);
  console.log(`VM Status: ${simulation.vm_status}`);
  console.log(`Gas Used: ${simulation.gas_used}`);

  if (!simulation.success) {
    console.log("\nTransaction would FAIL on-chain.");
    console.log("Fix the issue before submitting.");
  } else {
    console.log(`\nEvents: ${simulation.events?.length ?? 0}`);
    console.log(`Changes: ${simulation.changes?.length ?? 0}`);
    console.log("Transaction is safe to submit.");
  }

  return simulation;
}
```

### Pre-Flight Validation Before Submission

TypeScript
Python

```typescript
import { Aptos, AptosConfig, Network, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

async function simulateThenSubmit(sender: Account, payload: any) {
  // Step 1: Build the transaction
  const transaction = await aptos.transaction.build.simple({
    sender: sender.accountAddress,
    data: payload,
  });

  // Step 2: Simulate first
  const [simulation] = await aptos.transaction.simulate.simple({
    signerPublicKey: sender.publicKey,
    transaction,
  });

  if (!simulation.success) {
    throw new Error(
      `Simulation failed: ${simulation.vm_status}. Transaction not submitted.`
    );
  }

  console.log(`Simulation passed. Estimated gas: ${simulation.gas_used}`);

  // Step 3: Submit the real transaction
  const result = await aptos.signAndSubmitTransaction({
    signer: sender,
    transaction,
  });

  // Step 4: Wait for finality (1-3 seconds)
  const committed = await aptos.waitForTransaction({
    transactionHash: result.hash,
  });

  console.log(`Transaction committed: ${committed.success}`);
  return committed;
}
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import TransactionPayload

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

def simulate_then_submit(sender: Account, payload: TransactionPayload):
    """Simulate a transaction, then submit only if simulation succeeds."""
    # Step 1: Simulate
    sim_result = client.simulate_transaction(sender, payload)
    sim = sim_result[0]

    if not sim["success"]:
        raise RuntimeError(
            f"Simulation failed: {sim['vm_status']}. Not submitting."
        )

    print(f"Simulation passed. Estimated gas: {sim['gas_used']}")

    # Step 2: Submit for real
    tx_hash = client.submit_transaction(sender, payload)
    print(f"Submitted: {tx_hash}")

    # Step 3: Wait for finality
    result = client.wait_for_transaction(tx_hash)
    print(f"Committed: success={result['success']}")
    return result
```

## Common Use Cases

### Gas Estimation for Wallets

Simulate transactions before showing the user a confirmation dialog. Display the estimated gas cost and warn if the transaction would fail. This is the standard pattern for wallet applications.

### Error Debugging During Development

When a transaction fails unexpectedly, simulate it to get detailed error information without spending gas. The `vm_status` field provides Move abort codes and error messages that help pinpoint the issue.

### Batch Transaction Validation

Before submitting a batch of transactions, simulate each one to verify they would all succeed. This is especially important for multi-step workflows where later transactions depend on earlier ones.

## Movement-Specific Notes

- Simulation runs against the latest ledger state. If the chain state changes between simulation and submission, the actual result may differ. For volatile state (DEX prices, auction bids), re-simulate immediately before submitting.
- A zero-filled signature is a placeholder for simulation payloads, not a guarantee that any sender/auth-key combination will pass. Keep it for simulation-only requests and do not reuse it for actual submissions.
- Simulation gas usage is a close estimate but may differ slightly from actual execution due to BlockSTM parallel execution dynamics. Add a 10-20% buffer to simulated gas when setting `max_gas_amount` for the real transaction.
- Use `estimate_gas_unit_price=true` to get the node's recommended gas price based on current network conditions.

## Related Endpoints

- [`POST /v1/transactions`](https://www.dwellir.com/docs/movement/transactions) -- Submit the transaction after successful simulation.
- [`GET /v1/accounts/{address}`](https://www.dwellir.com/docs/movement/accounts) -- Get the current sequence number for simulation.
- [`POST /v1/view`](https://www.dwellir.com/docs/movement/modules_view) -- Read state without a transaction (for simpler queries).
- [`GET /v1/-/health`](https://www.dwellir.com/docs/movement/health) -- Verify the node is healthy before simulating.

---

## Transactions — Move REST API on Movement

# Transactions — Move REST API on Movement

## Overview

The transactions endpoint handles both submitting new signed transactions and querying existing ones on Movement. Submitting a transaction is the only way to change on-chain state: transferring tokens, calling entry functions, publishing modules, and interacting with DeFi protocols all require signed transactions.

Movement uses the Aptos transaction format with BCS (Binary Canonical Serialization) encoding. The Aptos SDKs handle serialization and signing automatically, but understanding the format is valuable for debugging and for building custom tooling.

With Movement's fast finality (1-3 seconds), submitted transactions reach a final, irreversible state almost immediately.

## Endpoints

| Method | Path                                        | Description                             |
| ------ | ------------------------------------------- | --------------------------------------- |
| `POST` | `/v1/transactions`                          | Submit a BCS-encoded signed transaction |
| `GET`  | `/v1/transactions/by_hash/{txn_hash}`       | Get transaction by hash                 |
| `GET`  | `/v1/transactions/by_version/{txn_version}` | Get transaction by ledger version       |
| `GET`  | `/v1/transactions`                          | List recent transactions                |

**Base URL:** `https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1`

## Transaction Lifecycle

1. **Build** -- Construct the transaction payload with sender, sequence number, gas parameters, and the function call.
2. **Sign** -- Sign the raw transaction bytes with the sender's Ed25519 private key.
3. **Submit** -- Send the signed transaction to the REST API.
4. **Pending** -- The transaction enters the mempool and is picked up by the sequencer.
5. **Committed** -- The transaction is included in a block and executed by the Move VM (1-3 seconds on Movement).
6. **Finalized** -- On Movement, committed transactions are immediately final due to BFT consensus.

## Submit a Transaction

### Endpoint

```
POST /v1/transactions
```

### Headers

| Header         | Value                                        | Required      |
| -------------- | -------------------------------------------- | ------------- |
| `Content-Type` | `application/x.aptos.signed_transaction+bcs` | Yes (for BCS) |

When submitting BCS-encoded transactions (recommended), set the content type to `application/x.aptos.signed_transaction+bcs` and send the raw BCS bytes as the request body. The SDKs handle this automatically.

### JSON Submission (Alternative)

You can also submit JSON-encoded transactions with `Content-Type: application/json`:

```json
{
  "sender": "0xYOUR_ADDRESS",
  "sequence_number": "42",
  "max_gas_amount": "10000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::coin::transfer",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0xRECIPIENT_ADDRESS", "1000000"]
  },
  "signature": {
    "type": "ed25519_signature",
    "public_key": "0xYOUR_PUBLIC_KEY",
    "signature": "0xSIGNATURE_HEX"
  }
}
```

### Request Fields

| Field                       | Type   | Required | Description                                                                                  |
| --------------------------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
| `sender`                    | string | Yes      | Sender's account address                                                                     |
| `sequence_number`           | string | Yes      | Account's current sequence number (nonce). Get from the accounts endpoint.                   |
| `max_gas_amount`            | string | Yes      | Maximum gas units the sender is willing to pay. Transaction fails if execution exceeds this. |
| `gas_unit_price`            | string | Yes      | Price per gas unit in octas (1 MOVE = 10^8 octas).                                           |
| `expiration_timestamp_secs` | string | Yes      | Unix timestamp after which the transaction expires. Set 30-60 seconds in the future.         |
| `payload`                   | object | Yes      | The transaction payload (see Transaction Types below).                                       |
| `signature`                 | object | Yes      | Ed25519 or multi-sig signature over the raw transaction bytes.                               |

### Response (202 Accepted)

```json
{
  "hash": "0x7a8c3b1f2e4d5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0",
  "sender": "0xYOUR_ADDRESS",
  "sequence_number": "42",
  "max_gas_amount": "10000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": {
    "type": "entry_function_payload",
    "function": "0x1::coin::transfer",
    "type_arguments": ["0x1::aptos_coin::AptosCoin"],
    "arguments": ["0xRECIPIENT_ADDRESS", "1000000"]
  }
}
```

The `202 Accepted` status means the transaction was received and will be processed. It does not guarantee execution success. Poll by hash to check the outcome.

## Transaction Types

### Entry Function Payload

The most common type. Calls a public `entry` function on a published module.

```json
{
  "type": "entry_function_payload",
  "function": "0x1::coin::transfer",
  "type_arguments": ["0x1::aptos_coin::AptosCoin"],
  "arguments": ["0xRECIPIENT", "1000000"]
}
```

### Script Payload

Executes an arbitrary Move script (compiled bytecode) inline. Used for complex multi-step operations that do not have a published module.

```json
{
  "type": "script_payload",
  "code": { "bytecode": "0x..." },
  "type_arguments": [],
  "arguments": []
}
```

### Module Bundle Payload

Publishes Move modules to the sender's account.

```json
{
  "type": "module_bundle_payload",
  "modules": [{ "bytecode": "0x..." }]
}
```

## Query Transactions

### By Hash

```
GET /v1/transactions/by_hash/{txn_hash}
```

Returns the full transaction details including execution result, gas used, events emitted, and state changes.

### By Version

```
GET /v1/transactions/by_version/{txn_version}
```

Every committed transaction has a unique, sequential version number. This is useful for indexing and pagination.

### Response (Committed Transaction)

```json
{
  "version": "125304892",
  "hash": "0x7a8c3b...",
  "state_change_hash": "0x...",
  "event_root_hash": "0x...",
  "state_checkpoint_hash": "0x...",
  "gas_used": "542",
  "success": true,
  "vm_status": "Executed successfully",
  "accumulator_root_hash": "0x...",
  "changes": [
    {
      "address": "0xYOUR_ADDRESS",
      "state_key_hash": "0x...",
      "data": {
        "type": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
        "data": { "coin": { "value": "999000" } }
      },
      "type": "write_resource"
    }
  ],
  "sender": "0xYOUR_ADDRESS",
  "sequence_number": "42",
  "max_gas_amount": "10000",
  "gas_unit_price": "100",
  "expiration_timestamp_secs": "1700000000",
  "payload": { "..." : "..." },
  "signature": { "..." : "..." },
  "events": [
    {
      "guid": { "creation_number": "3", "account_address": "0xYOUR_ADDRESS" },
      "sequence_number": "8",
      "type": "0x1::coin::WithdrawEvent",
      "data": { "amount": "1000000" }
    }
  ],
  "timestamp": "1699999950000000",
  "type": "user_transaction"
}
```

### Key Response Fields

| Field       | Type    | Description                             |
| ----------- | ------- | --------------------------------------- |
| `version`   | string  | Unique sequential ledger version        |
| `hash`      | string  | Transaction hash (use for lookups)      |
| `success`   | boolean | Whether execution succeeded             |
| `vm_status` | string  | Human-readable execution status         |
| `gas_used`  | string  | Actual gas consumed                     |
| `events`    | array   | Events emitted during execution         |
| `changes`   | array   | State changes (resource writes/deletes) |
| `timestamp` | string  | Block timestamp in microseconds         |

## Code Examples

### Transfer Tokens

cURL
Python
TypeScript

```bash
# Submit a JSON-encoded transaction (for demonstration)
# In production, use BCS encoding via an SDK
curl -X POST "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": "0xYOUR_ADDRESS",
    "sequence_number": "42",
    "max_gas_amount": "10000",
    "gas_unit_price": "100",
    "expiration_timestamp_secs": "1700000000",
    "payload": {
      "type": "entry_function_payload",
      "function": "0x1::coin::transfer",
      "type_arguments": ["0x1::aptos_coin::AptosCoin"],
      "arguments": ["0xRECIPIENT_ADDRESS", "1000000"]
    },
    "signature": {
      "type": "ed25519_signature",
      "public_key": "0xYOUR_PUBLIC_KEY",
      "signature": "0xYOUR_SIGNATURE"
    }
  }'
```

```python
from aptos_sdk.client import RestClient
from aptos_sdk.account import Account
from aptos_sdk.transactions import (
    EntryFunction,
    TransactionArgument,
    TransactionPayload,
)

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")
sender = Account.load_key("YOUR_PRIVATE_KEY_HEX")

# Transfer 1 MOVE (10^8 octas)
payload = EntryFunction.natural(
    "0x1::coin",
    "transfer",
    ["0x1::aptos_coin::AptosCoin"],
    [
        TransactionArgument(
            bytes.fromhex("RECIPIENT_ADDRESS_WITHOUT_0x"),
            TransactionArgument.ADDRESS,
        ),
        TransactionArgument(100_000_000, TransactionArgument.U64),
    ],
)

tx_hash = client.submit_transaction(sender, TransactionPayload(payload))
print(f"Submitted: {tx_hash}")

# Wait for finality (1-3 seconds on Movement)
result = client.wait_for_transaction(tx_hash)
print(f"Success: {result['success']}")
print(f"Gas used: {result['gas_used']}")
```

```typescript
import { Aptos, AptosConfig, Network, Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const sender = Account.fromPrivateKey({
  privateKey: new Ed25519PrivateKey("YOUR_PRIVATE_KEY"),
});

// Build the transaction
const transaction = await aptos.transaction.build.simple({
  sender: sender.accountAddress,
  data: {
    function: "0x1::coin::transfer",
    typeArguments: ["0x1::aptos_coin::AptosCoin"],
    functionArguments: ["0xRECIPIENT_ADDRESS", "100000000"], // 1 MOVE
  },
});

// Sign and submit
const result = await aptos.signAndSubmitTransaction({
  signer: sender,
  transaction,
});

console.log(`Submitted: ${result.hash}`);

// Wait for finality
const committed = await aptos.waitForTransaction({
  transactionHash: result.hash,
});

console.log(`Success: ${committed.success}`);
console.log(`Gas used: ${committed.gas_used}`);
```

### Query Transaction by Hash

cURL
Python
TypeScript

```bash
# Get transaction details by hash
TX_HASH="0x7a8c3b1f2e4d5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0"
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions/by_hash/$TX_HASH" \
  -H "Accept: application/json" | jq '{success, gas_used, vm_status, events_count: (.events | length)}'
```

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

tx_hash = "0x7a8c3b..."
tx = client.transaction_by_hash(tx_hash)

print(f"Success: {tx['success']}")
print(f"Gas used: {tx['gas_used']}")
print(f"VM status: {tx['vm_status']}")
print(f"Events emitted: {len(tx.get('events', []))}")
for event in tx.get("events", []):
    print(f"  {event['type']}: {event['data']}")
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

const tx = await aptos.getTransactionByHash({
  transactionHash: "0x7a8c3b...",
});

if ("success" in tx) {
  console.log(`Success: ${tx.success}`);
  console.log(`Gas used: ${tx.gas_used}`);
  console.log(`Events: ${tx.events?.length ?? 0}`);
}
```

### List Recent Transactions

cURL
TypeScript

```bash
# List the 5 most recent transactions
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions?limit=5" \
  -H "Accept: application/json" | jq '.[] | {version, hash: .hash[0:16], type: .type, success}'

# List transactions starting from a specific version
curl -s "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1/transactions?start=125304890&limit=10" \
  -H "Accept: application/json" | jq '.[].version'
```

```typescript
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";

const config = new AptosConfig({
  network: Network.CUSTOM,
  fullnode: "https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1",
});
const aptos = new Aptos(config);

// Get recent transactions
const transactions = await aptos.getTransactions({ options: { limit: 5 } });
for (const tx of transactions) {
  console.log(`Version ${tx.version}: ${tx.type}`);
}
```

## Error Handling

### Common Error Responses

| Status | Error Code                | Description                                                           |
| ------ | ------------------------- | --------------------------------------------------------------------- |
| `400`  | `invalid_transaction`     | Malformed payload, missing fields, or BCS encoding error              |
| `400`  | `sequence_number_too_old` | Sequence number already used (transaction replayed or nonce conflict) |
| `400`  | `sequence_number_too_new` | Gap in sequence numbers (previous transaction not yet committed)      |
| `400`  | `transaction_expired`     | `expiration_timestamp_secs` is in the past                            |
| `400`  | `insufficient_balance`    | Account cannot cover gas costs                                        |
| `404`  | `transaction_not_found`   | Hash does not match any known transaction                             |
| `413`  | `payload_too_large`       | Transaction exceeds size limit                                        |

### Handling Sequence Number Conflicts

```python
from aptos_sdk.client import RestClient

client = RestClient("https://api-movement-mainnet.n.dwellir.com/YOUR_API_KEY/v1")

def submit_with_retry(sender, payload, max_retries=3):
    """Submit a transaction with automatic sequence number refresh on conflict."""
    for attempt in range(max_retries):
        try:
            tx_hash = client.submit_transaction(sender, payload)
            return client.wait_for_transaction(tx_hash)
        except Exception as e:
            if "sequence_number" in str(e).lower() and attempt < max_retries - 1:
                # Refresh the account's sequence number and retry
                print(f"Sequence number conflict, retrying (attempt {attempt + 2})")
                continue
            raise
```

## Common Use Cases

### Token Transfers

The most basic transaction type. Transfer MOVE or any fungible token between accounts using `0x1::coin::transfer` or `0x1::aptos_account::transfer`.

### Smart Contract Interaction

Call any `entry` function on a published Move module. This covers DeFi operations (swaps, deposits, borrowing), NFT minting, governance voting, and all other on-chain actions.

### Module Publishing

Deploy new Move modules to your account using the module bundle payload type. This is how smart contracts are published on Movement.

## Movement-Specific Notes

- **Fast finality** -- Transactions confirm in 1-3 seconds on Movement. Set polling intervals accordingly.
- **BCS encoding** -- Always prefer BCS-encoded submissions in production. JSON submission works but is less efficient and requires pre-computed signatures.
- **Gas estimation** -- Use the simulation endpoint to estimate gas before submitting. Movement gas prices are typically lower than Ethereum L1 but vary with network load.
- **Expiration** -- Set `expiration_timestamp_secs` to 30-60 seconds in the future. With fast finality, transactions that do not execute within seconds likely have issues.

## Related Endpoints

- [`POST /v1/transactions/simulate`](https://www.dwellir.com/docs/movement/transaction_simulate) -- Simulate a transaction to preview gas costs and execution result.
- [`GET /v1/accounts/{address}`](https://www.dwellir.com/docs/movement/accounts) -- Get the current sequence number for the sender account.
- [`GET /v1/accounts/{address}/events/{creation_number}`](https://www.dwellir.com/docs/movement/events) -- Query events emitted by transactions.
- [`POST /v1/view`](https://www.dwellir.com/docs/movement/modules_view) -- Read on-chain state without submitting a transaction.

---

## NeuroWeb RPC Documentation

# NeuroWeb RPC Documentation

## NeuroWeb RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where NeuroWeb supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Overview

NeuroWeb is a decentralized AI blockchain and Polkadot parachain designed to incentivize knowledge creation, connectivity, and sharing through Knowledge Mining. Built on the Substrate framework and evolved from OriginTrail Parachain, NeuroWeb enables the creation and management of verifiable knowledge assets, powering the Decentralized Knowledge Graph (DKG) that organizes humanity's most important assets.

This documentation provides comprehensive coverage of NeuroWeb's JSON-RPC API methods, enabling developers to interact with NeuroWeb nodes for building applications, wallets, explorers, and other blockchain tools.

## Network Information

### Mainnet (NeuroWeb)

| Parameter        | Value                                                  | Details |
| ---------------- | ------------------------------------------------------ | ------- |
| Parachain ID     | 2043                                                   |         |
| Native Token     | NEURO                                                  |         |
| Consensus        | Nominated Proof-of-Stake (NPoS) via Polkadot           |         |
| Framework        | Substrate                                              |         |
| Special Features | EVM-enabled, Decentralized Knowledge Graph, AI-focused |         |

## Connection Endpoints

### HTTPS Endpoint

```
https://api-neuroweb.n.dwellir.com/{YOUR_API_KEY}
```

### WebSocket Endpoint

```
wss://api-neuroweb.n.dwellir.com/{YOUR_API_KEY}
```

## Authentication

Authentication is done via the URL path. Replace `{YOUR_API_KEY}` with your actual API key obtained from [dwellir.com](https://www.dwellir.com).

## API Categories

NeuroWeb's RPC API is organized into the following method categories:

### Core APIs

#### Author Methods

Submit and manage extrinsics (transactions) on the network.

#### Chain Methods

Query blockchain data including blocks, headers, and finalized state.

#### State Methods

Access runtime storage, metadata, and proof generation.

#### System Methods

Node information, health checks, and network properties.

### Specialized APIs

#### BEEFY Methods

Bridge Efficiency Enabling Finality Yielder protocol operations.

#### Grandpa Methods

GRANDPA finality gadget operations and proofs.

#### Child State Methods

Manage child storage tries for contracts and parachains.

#### Sync State Methods

Monitor and manage node synchronization state.

## Quick Start Examples

### Get Latest Block

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_getBlock',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Latest block:', data.result);
```

### Submit Transaction

```python
import requests
import json

url = "https://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
headers = {
    "Content-Type": "application/json"
}

# Properly formatted and signed extrinsic
extrinsic = "0x..."

payload = {
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": [extrinsic],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
tx_hash = response.json()["result"]
print(f"Transaction hash: {tx_hash}")
```

### Subscribe to New Blocks (WebSocket)

```javascript
const WebSocket = require('ws');

const ws = new WebSocket('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_subscribeNewHeads',
    params: [],
    id: 1
  }));
});

ws.on('message', (data) => {
  const response = JSON.parse(data);
  if (response.params?.result) {
    console.log('New block:', response.params.result);
  }
});
```

## Error Handling

NeuroWeb RPC errors follow the JSON-RPC 2.0 error format:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "Expected hex-encoded hash"
  },
  "id": 1
}
```

### Common Error Codes

| Code   | Message          | Description               |
| ------ | ---------------- | ------------------------- |
| -32700 | Parse error      | Invalid JSON              |
| -32600 | Invalid request  | Missing required fields   |
| -32601 | Method not found | Unknown RPC method        |
| -32602 | Invalid params   | Invalid method parameters |
| -32603 | Internal error   | Node processing error     |
| -32000 | Server error     | Custom server errors      |

## Best Practices

### 1. Connection Management

- Use WebSocket connections for subscriptions and real-time updates
- Implement reconnection logic for WebSocket disconnections
- Use HTTPS for single queries and transactions

### 2. Error Handling

- Always check for error responses before processing results
- Implement retry logic with exponential backoff
- Log errors for debugging and monitoring

### 3. Performance Optimization

- Batch multiple queries when possible
- Cache frequently accessed data like metadata
- Use specific block hashes for deterministic queries

### 4. Security

- Never expose API keys in client-side code
- Validate all input data before submission
- Use secure storage for private keys

## SDK Support

### Official Libraries

- **@polkadot/api** - JavaScript/TypeScript SDK (compatible with NeuroWeb)
- **py-substrate-interface** - Python SDK
- **subxt** - Rust SDK
- **go-substrate-rpc-client** - Go SDK

### Integration Example

```javascript
// Using @polkadot/api
const { ApiPromise, WsProvider } = require('@polkadot/api');

async function connect() {
  const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');

  const api = await ApiPromise.create({ provider });

  // Query chain data
  const chain = await api.rpc.system.chain();
  console.log(`Connected to ${chain}`);

  // Get account balance
  const account = 'YOUR_ADDRESS';
  const { data: balance } = await api.query.system.account(account);
  console.log(`Balance: ${balance.free.toString()}`);

  return api;
}
```

## NeuroWeb Features

### Decentralized Knowledge Graph

NeuroWeb powers the Decentralized Knowledge Graph (DKG), enabling the creation and management of verifiable knowledge assets. The network has scaled to support billions of interconnected knowledge assets with recent V8 improvements.

### AI-Focused Infrastructure

As a decentralized AI blockchain, NeuroWeb incentivizes knowledge creation and sharing through Knowledge Mining, providing infrastructure for AI applications that require verifiable, trustworthy data.

### EVM Compatibility

NeuroWeb is EVM-enabled, allowing developers to deploy Ethereum-compatible smart contracts alongside Substrate-native pallets, providing flexibility for various application architectures.

### Polkadot Integration

As a Polkadot parachain, NeuroWeb benefits from:

- **Shared Security**: Protected by Polkadot's validator network
- **Cross-Chain Interoperability**: Seamless communication with other parachains
- **Scalability**: Leveraging Polkadot's multi-chain architecture

## Additional Resources

- [NeuroWeb Official Website](https://neuroweb.ai/)
- [NeuroWeb Documentation](https://docs.neuroweb.ai/)
- [OriginTrail Documentation](https://docs.origintrail.io/)
- [NeuroWeb GitHub](https://github.com/OriginTrail/neuroweb)
- [Polkadot Parachains Info](https://parachains.info/details/neuroweb)
- [Substrate Documentation](https://docs.substrate.io/)

## Support

For additional support or questions:

- Email: <support@dwellir.com>
- Documentation: [dwellir.com/docs](https://www.dwellir.com/docs)

***

## Method Categories

Select a category below to explore detailed method documentation:

---

## author_pendingExtrinsics - Neuroweb RPC Method

# author_pendingExtrinsics - Neuroweb RPC Method

Returns all pending extrinsics currently in the transaction pool on Neuroweb. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`author_pendingExtrinsics` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Neuroweb
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Neuroweb transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/neuroweb/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/neuroweb/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/neuroweb/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Neuroweb RPC Method

# author_rotateKeys - Neuroweb RPC Method

Generate a new set of session keys on Neuroweb. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`author_rotateKeys` is critical for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Validator Setup** - Generate initial session keys when setting up a new validator on decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Neuroweb:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/neuroweb/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/neuroweb/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Neuroweb RPC Method

# author_submitAndWatchExtrinsic - Neuroweb RPC Method

Submits a signed extrinsic to Neuroweb and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Neuroweb
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/neuroweb/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/neuroweb/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/neuroweb/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Neuroweb RPC Method

# author_submitExtrinsic - Neuroweb RPC Method

Submits a fully signed extrinsic to Neuroweb for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`author_submitExtrinsic` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Token Transfers** -- Send native tokens or assets between accounts on Neuroweb
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/neuroweb/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/neuroweb/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Neuroweb RPC Method

# beefy_getFinalizedHead - Neuroweb RPC Method

Returns the block hash of the latest BEEFY-finalized block on Neuroweb. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`beefy_getFinalizedHead` is important for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/neuroweb/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Neuroweb RPC Method

# chain_getBlock - Neuroweb RPC Method

Retrieves complete block information from Neuroweb, including the block header, extrinsics, and justifications.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/neuroweb/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/neuroweb/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Neuroweb RPC Method

# chain_getBlockHash - Neuroweb RPC Method

Returns the block hash for a given block number on Neuroweb. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`chain_getBlockHash` is fundamental for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Neuroweb
- **Block Navigation** - Navigate the blockchain history for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Neuroweb
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Neuroweb for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Neuroweb state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Neuroweb network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/neuroweb/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Neuroweb RPC Method

# chain_getFinalizedHead - Neuroweb RPC Method

Returns the hash of the last finalized block on Neuroweb. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`chain_getFinalizedHead` is critical for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Neuroweb
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Neuroweb:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/neuroweb/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/neuroweb/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Neuroweb RPC Method

# chain_getHeader - Neuroweb RPC Method

Returns the block header for a given hash on Neuroweb. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`chain_getHeader` is ideal for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Neuroweb
- **Chain Synchronization** - Track block production and monitor chain progress for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Neuroweb:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Neuroweb chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Neuroweb block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/neuroweb/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Neuroweb RPC Method

# chain_subscribeFinalizedHeads - Neuroweb RPC Method

Subscribe to receive notifications when blocks are finalized on Neuroweb. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Exchange Deposits** - Only credit funds after finalization for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Neuroweb:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/neuroweb/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Neuroweb RPC Method

# chain_subscribeNewHeads - Neuroweb RPC Method

Subscribe to receive notifications when new block headers are produced on Neuroweb. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`chain_subscribeNewHeads` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Block Monitoring** - Track new blocks in real time on Neuroweb for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Neuroweb as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Neuroweb:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/neuroweb/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/neuroweb/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## eth_accounts - List available accounts

# eth_accounts - List available accounts

List available accounts on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_accounts",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_blockNumber - Get Latest Block Number

# eth_blockNumber - Get Latest Block Number

Returns the number of the most recent block on Neuroweb Mainnet.

## When to Use This Method

`eth_blockNumber` is fundamental for:

- **Syncing Applications** - Keep your dApp in sync with the latest blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): **Type**: Hexadecimal string **Format**: `0x` prefixed **Example**: `0x5bad55` (6008149 in decimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5bad55"
}
```

## Error Responses

### Error 1

- Code: `-32603`
- Description: Internal error

### Error 2

- Code: `-32005`
- Description: Rate limit exceeded

### Error 3

- Code: `-32000`
- Description: Execution reverted

## Implementation Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch API
const getBlockNumber = async () => {
  const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_blockNumber',
      params: [],
      id: 1
    })
  });
  
  const data = await response.json();
  const blockNumber = parseInt(data.result, 16);
  console.log('Current block:', blockNumber);
  return blockNumber;
};

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Current block:', blockNumber);
```

```python
import requests
import json

def get_block_number():
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
    
    payload = {
        "jsonrpc": "2.0",
        "method": "eth_blockNumber",
        "params": [],
        "id": 1
    }
    
    response = requests.post(url, json=payload)
    data = response.json()
    
    # Convert hex to decimal
    block_number = int(data['result'], 16)
    print(f"Current block: {block_number}")
    return block_number

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'))
block_number = w3.eth.block_number
print(f"Current block: {block_number}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }
    
    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Current block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations:

```javascript
async function getConfirmations(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;
  
  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(txHash, confirmations = 6) {
  let currentConfirmations = 0;
  
  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000)); // Check every 2 seconds
  }
  
  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks:

```javascript
async function getRecentEvents(contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;
  
  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);
  
  return events;
}
```

### 3. Node Health Monitoring

Check if your node is synced:

```javascript
async function checkNodeHealth() {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);
    
    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;
    
    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }
    
    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) { // 2 second cache
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }
  
  async get(provider) {
    const now = Date.now();
    
    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }
    
    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }
  
  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

---

## eth_call - Execute Smart Contract Calls

# eth_call - Execute Smart Contract Calls

**Alchemy** = $11.70 per million `eth_call` requests\
**Quicknode** = $12.40 per million `eth_call` requests\
**Dwellir** = $2 per million `eth_call` requests

Quicknode is **6X more expensive** for `eth_call`s!

[Switch to Dwellir today](https://dashboard.dwellir.com/register)

Executes a new message call immediately without creating a transaction on the blockchain. Used for reading smart contract state.

## When to Use This Method

`eth_call` is essential for:

- **Reading Contract State** - Query view/pure functions
- **Simulating Transactions** - Test execution without gas costs
- **DeFi Integrations** - Check prices, balances, allowances
- **Complex Queries** - Execute multi-step contract logic

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Common Use Cases

### 1. DeFi Price Queries

```javascript
// Uniswap V3 Pool Price Query
async function getPoolPrice(poolAddress) {
  const poolABI = [
    "function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)",
    "function token0() view returns (address)",
    "function token1() view returns (address)"
  ];
  
  const pool = new Contract(poolAddress, poolABI, provider);
  
  const [slot0, token0, token1] = await Promise.all([
    pool.slot0(),
    pool.token0(),
    pool.token1()
  ]);
  
  // Calculate price from sqrtPriceX96
  const sqrtPriceX96 = slot0.sqrtPriceX96;
  const price = (Number(sqrtPriceX96) / (2 ** 96)) ** 2;
  
  return {
    token0: token0,
    token1: token1,
    price: price,
    tick: slot0.tick
  };
}
```

### 2. Multi-Contract Queries

```javascript
// Batch multiple contract calls
async function multicall(calls) {
  const multicallABI = [
    "function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)"
  ];
  
  const multicallAddress = "0xcA11bde05977b3631167028862bE2a173976CA11"; // Neuroweb Multicall3
  const multicall = new Contract(multicallAddress, multicallABI, provider);
  
  const results = await multicall.aggregate(calls);
  return results.returnData;
}
```

### 3. Access Control Checks

```javascript
// Check permissions before transaction
async function checkPermissions(contractAddress, userAddress, role) {
  const accessControlABI = [
    "function hasRole(bytes32 role, address account) view returns (bool)",
    "function getRoleAdmin(bytes32 role) view returns (bytes32)"
  ];
  
  const contract = new Contract(contractAddress, accessControlABI, provider);
  const hasRole = await contract.hasRole(role, userAddress);
  
  return hasRole;
}
```

---

## eth_chainId - Get chain ID

# eth_chainId - Get chain ID

Get chain ID on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_chainId",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_chainId',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_coinbase - Get coinbase address

# eth_coinbase - Get coinbase address

Get coinbase address on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_coinbase",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_estimateGas - Estimate Transaction Gas

# eth_estimateGas - Estimate Transaction Gas

Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain.

## When to Use This Method

`eth_estimateGas` is crucial for:

- **Transaction Preparation** - Calculate gas limits before sending
- **Cost Estimation** - Preview transaction fees for users
- **Gas Optimization** - Find optimal gas usage for complex operations
- **Error Prevention** - Detect failures before broadcasting

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Common Use Cases

### 1. Pre-Transaction Validation

```javascript
// Validate transaction before sending
async function validateTransaction(from, to, value, data) {
  try {
    const gasEstimate = await provider.estimateGas({
      from: from,
      to: to,
      value: value,
      data: data
    });
    
    // Check if account has enough balance
    const balance = await provider.getBalance(from);
    const feeData = await provider.getFeeData();
    const maxCost = value + (gasEstimate * feeData.maxFeePerGas);
    
    if (balance < maxCost) {
      return {
        valid: false,
        reason: 'Insufficient balance',
        required: ethers.formatEther(maxCost),
        available: ethers.formatEther(balance)
      };
    }
    
    return {
      valid: true,
      gasLimit: gasEstimate.toString(),
      estimatedFee: ethers.formatEther(gasEstimate * feeData.gasPrice)
    };
  } catch (error) {
    return {
      valid: false,
      reason: error.message
    };
  }
}
```

### 2. Dynamic Gas Pricing UI

```javascript
// Real-time gas price updates for UI
class GasPriceMonitor {
  constructor(provider) {
    this.provider = provider;
    this.listeners = [];
  }
  
  async getCurrentPrices() {
    const [feeData, block] = await Promise.all([
      this.provider.getFeeData(),
      this.provider.getBlock('latest')
    ]);
    
    return {
      slow: {
        maxFeePerGas: feeData.maxFeePerGas * 90n / 100n,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * 80n / 100n,
        estimatedTime: '2-5 minutes'
      },
      standard: {
        maxFeePerGas: feeData.maxFeePerGas,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
        estimatedTime: '15-30 seconds'
      },
      fast: {
        maxFeePerGas: feeData.maxFeePerGas * 120n / 100n,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * 150n / 100n,
        estimatedTime: '5-15 seconds'
      },
      baseFee: block.baseFeePerGas
    };
  }
  
  async estimateForTransaction(tx, speed = 'standard') {
    const prices = await this.getCurrentPrices();
    const gasEstimate = await this.provider.estimateGas(tx);
    const settings = prices[speed];
    
    return {
      gasLimit: gasEstimate,
      ...settings,
      estimatedCost: ethers.formatEther(gasEstimate * settings.maxFeePerGas),
      maxCost: ethers.formatEther(gasEstimate * settings.maxFeePerGas)
    };
  }
}
```

### 3. Batch Operation Optimization

```javascript
// Optimize gas for batch operations
async function optimizeBatchTransactions(transactions) {
  const estimates = [];
  let totalGas = 0n;
  
  // Estimate individually
  for (const tx of transactions) {
    const estimate = await provider.estimateGas(tx);
    estimates.push(estimate);
    totalGas += estimate;
  }
  
  // Check if multicall is more efficient
  const multicallEstimate = await estimateMulticall(transactions);
  
  if (multicallEstimate < totalGas * 90n / 100n) {
    return {
      method: 'multicall',
      gasLimit: multicallEstimate,
      savings: ethers.formatUnits(totalGas - multicallEstimate, 'gwei')
    };
  }
  
  return {
    method: 'individual',
    gasLimits: estimates,
    totalGas: totalGas
  };
}
```

---

## eth_feeHistory - Get historical gas prices

# eth_feeHistory - Get historical gas prices

Returns historical gas information for the Neuroweb network. This method is useful for gas price estimation and understanding network congestion patterns over time.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_feeHistory",
        "params": ["0x4", "latest", [25, 50, 75]],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `oldestBlock`: `QUANTITY` - Lowest block number returned `baseFeePerGas`: `Array` - Array of base fees per gas for each block `gasUsedRatio`: `Array` - Array of gas used ratios for each block (0.0 to 1.0) `reward`: `Array` - Array of arrays containing priority fees at requested percentiles

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1a2b3c4",
    "baseFeePerGas": [
      "0x3b9aca00",
      "0x3b9aca00",
      "0x3b9aca00",
      "0x3b9aca00"
    ],
    "gasUsedRatio": [0.5, 0.6, 0.4, 0.7],
    "reward": [
      ["0x77359400", "0x77359400", "0x77359400"],
      ["0x77359400", "0x77359400", "0x77359400"],
      ["0x77359400", "0x77359400", "0x77359400"]
    ]
  }
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x4", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0x4', 'latest', [25, 50, 75]],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_gasPrice - Get Current Gas Price

# eth_gasPrice - Get Current Gas Price

Returns the current gas price in wei. This represents the median gas price from recent blocks on Neuroweb Mainnet.

## When to Use This Method

`eth_gasPrice` is essential for:

- **Transaction Pricing** - Set appropriate gas prices for transactions
- **Fee Estimation** - Calculate transaction costs for users
- **Gas Strategy** - Optimize transaction speed vs cost
- **Market Monitoring** - Track network congestion levels

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Common Use Cases

### 1. Dynamic Fee Adjustment

```javascript
// Dynamically adjust fees based on network conditions
async function getOptimalGasPrice(urgency = 'standard') {
  const gasPrice = await provider.getGasPrice();
  const block = await provider.getBlock('latest');
  const baseFee = block.baseFeePerGas;
  
  const multipliers = {
    low: 0.9,
    standard: 1.0,
    high: 1.2,
    urgent: 1.5
  };
  
  const multiplier = multipliers[urgency] || 1.0;
  const adjustedPrice = gasPrice * BigInt(Math.floor(multiplier * 100)) / 100n;
  
  // For EIP-1559 transactions
  const maxPriorityFee = adjustedPrice - baseFee;
  const maxFeePerGas = baseFee * 2n + maxPriorityFee;
  
  return {
    legacy: {
      gasPrice: adjustedPrice,
      formatted: formatGwei(adjustedPrice) + ' gwei'
    },
    eip1559: {
      maxFeePerGas: maxFeePerGas,
      maxPriorityFeePerGas: maxPriorityFee,
      formatted: {
        maxFee: formatGwei(maxFeePerGas) + ' gwei',
        priorityFee: formatGwei(maxPriorityFee) + ' gwei'
      }
    },
    estimatedConfirmationBlocks: urgency === 'urgent' ? 1 : urgency === 'high' ? 2 : 3
  };
}
```

### 2. Gas Price Oracle

```javascript
// Create a gas price oracle with caching
class GasPriceOracle {
  constructor(provider, cacheTime = 5000) {
    this.provider = provider;
    this.cacheTime = cacheTime;
    this.cache = null;
    this.lastFetch = 0;
  }
  
  async getPrice() {
    const now = Date.now();
    
    if (this.cache && (now - this.lastFetch) < this.cacheTime) {
      return this.cache;
    }
    
    const gasPrice = await this.provider.getGasPrice();
    
    this.cache = {
      wei: gasPrice,
      gwei: formatGwei(gasPrice),
      timestamp: now
    };
    this.lastFetch = now;
    
    return this.cache;
  }
  
  async getPriceWithRecommendations() {
    const price = await this.getPrice();
    const gweiPrice = parseFloat(price.gwei);
    
    return {
      ...price,
      recommendations: {
        sendNow: gweiPrice < 1,
        waitSuggested: gweiPrice > 5,
        congestionLevel: gweiPrice < 0.5 ? 'low' : gweiPrice < 2 ? 'normal' : 'high'
      }
    };
  }
}
```

### 3. Transaction Cost Calculator

```javascript
// Calculate and display transaction costs
async function calculateDetailedCosts(gasLimit) {
  const gasPrice = await provider.getGasPrice();
  const ethPrice = 3000; // Would fetch from price feed
  
  const costs = {
    slow: gasPrice * 90n / 100n,
    standard: gasPrice,
    fast: gasPrice * 120n / 100n
  };
  
  const results = {};
  
  for (const [speed, price] of Object.entries(costs)) {
    const totalWei = price * BigInt(gasLimit);
    const totalETH = Number(formatEther(totalWei));
    
    results[speed] = {
      gasPrice: formatGwei(price) + ' gwei',
      totalETH: totalETH.toFixed(6) + ' ETH',
      totalUSD: '$' + (totalETH * ethPrice).toFixed(2),
      percentOfTransfer: gasLimit === 21000 ? 'N/A' : 
        ((Number(totalWei) / Number(parseEther('1'))) * 100).toFixed(3) + '%'
    };
  }
  
  return results;
}
```

---

## eth_getBalance - Query Account Balance

# eth_getBalance - Query Account Balance

Returns the ETH balance of a given address on Neuroweb Mainnet.

## When to Use This Method

`eth_getBalance` is essential for:

- **Wallet Applications** - Display user balances
- **Transaction Validation** - Check if account has sufficient funds
- **DeFi Applications** - Monitor collateral and liquidity
- **Account Monitoring** - Track balance changes over time

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): **Type**: Hexadecimal string **Unit**: Wei (1 ETH = 10^18 wei) **Format**: `0x` prefixed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Error Responses

### Error 1

- Code: `-32602`
- Description: Invalid address format

### Error 2

- Code: `-32602`
- Description: Invalid block parameter

### Error 3

- Code: `-32000`
- Description: Account not found

## Implementation Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using ethers.js
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY');

async function getBalance(address) {
  // Get balance in wei
  const balanceWei = await provider.getBalance(address);
  
  // Convert to ETH
  const balanceEth = formatEther(balanceWei);
  
  console.log(`Balance: ${balanceEth} ETH`);
  return balanceEth;
}

// Check multiple balances
async function getMultipleBalances(addresses) {
  const balances = await Promise.all(
    addresses.map(async (addr) => {
      const balance = await provider.getBalance(addr);
      return {
        address: addr,
        balance: formatEther(balance)
      };
    })
  );
  return balances;
}
```

```python
from web3 import Web3

# Connect to Ethereum
w3 = Web3(Web3.HTTPProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'))

def get_balance(address):
    # Get balance in wei
    balance_wei = w3.eth.get_balance(address)
    
    # Convert to ETH
    balance_eth = w3.from_wei(balance_wei, 'ether')
    
    print(f"Balance: {balance_eth} ETH")
    return balance_eth

# Get balance at specific block
def get_historical_balance(address, block_number):
    balance_wei = w3.eth.get_balance(address, block_identifier=block_number)
    return w3.from_wei(balance_wei, 'ether')

# Monitor balance changes
def monitor_balance(address, interval=2):
    import time
    last_balance = 0
    
    while True:
        current_balance = w3.eth.get_balance(address)
        if current_balance != last_balance:
            change = current_balance - last_balance
            print(f"Balance changed: {w3.from_wei(change, 'ether')} ETH")
            last_balance = current_balance
        time.sleep(interval)
```

```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-neuroweb.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }
    
    address := common.HexToAddress("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb")
    
    // Get balance at latest block
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    
    // Convert wei to ETH
    ethValue := new(big.Float).Quo(
        new(big.Float).SetInt(balance),
        big.NewFloat(1e18),
    )
    
    fmt.Printf("Balance: %f ETH\n", ethValue)
}
```

## Common Use Cases

### 1. Wallet Balance Display

Display formatted balance with USD value:

```javascript
async function displayWalletBalance(address) {
  const provider = new JsonRpcProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
  
  // Get ETH balance
  const balance = await provider.getBalance(address);
  const ethBalance = formatEther(balance);
  
  // Get ETH price (from your price oracle)
  const ethPrice = await getEthPrice(); // Implement this
  const usdValue = parseFloat(ethBalance) * ethPrice;
  
  return {
    eth: ethBalance,
    usd: usdValue.toFixed(2),
    formatted: `${ethBalance} ETH ($${usdValue.toFixed(2)})`
  };
}
```

### 2. Transaction Pre-validation

Check if account has enough balance for transaction:

```javascript
async function canAffordTransaction(from, to, value, gasLimit, maxFeePerGas) {
  const balance = await provider.getBalance(from);
  
  // Calculate total cost
  const valueBigInt = BigInt(value);
  const gasCost = BigInt(gasLimit) * BigInt(maxFeePerGas);
  const totalCost = valueBigInt + gasCost;
  
  if (balance < totalCost) {
    const shortage = formatEther(totalCost - balance);
    throw new Error(`Insufficient balance. Need ${shortage} more ETH`);
  }
  
  return true;
}
```

### 3. Balance Change Detection

Monitor account for balance changes:

```javascript
class BalanceMonitor {
  constructor(provider, address) {
    this.provider = provider;
    this.address = address;
    this.lastBalance = null;
  }
  
  async start(callback, interval = 2000) {
    setInterval(async () => {
      const currentBalance = await this.provider.getBalance(this.address);
      
      if (this.lastBalance && currentBalance !== this.lastBalance) {
        const change = currentBalance - this.lastBalance;
        callback({
          address: this.address,
          previousBalance: this.lastBalance,
          currentBalance,
          change,
          changeFormatted: formatEther(change)
        });
      }
      
      this.lastBalance = currentBalance;
    }, interval);
  }
}

// Usage
const monitor = new BalanceMonitor(provider, "0x...");
monitor.start((data) => {
  console.log(`Balance changed by ${data.changeFormatted} ETH`);
});
```

### 4. Historical Balance Query

Get balance at specific block:

```javascript
async function getBalanceHistory(address, blocks) {
  const history = [];
  
  for (const blockNumber of blocks) {
    const balance = await provider.getBalance(address, blockNumber);
    const block = await provider.getBlock(blockNumber);
    
    history.push({
      block: blockNumber,
      timestamp: block.timestamp,
      balance: formatEther(balance)
    });
  }
  
  return history;
}

// Get balance every 1000 blocks
async function getBalanceSnapshots(address, count = 10) {
  const currentBlock = await provider.getBlockNumber();
  const blocks = [];
  
  for (let i = 0; i < count; i++) {
    blocks.push(currentBlock - (i * 1000));
  }
  
  return getBalanceHistory(address, blocks);
}
```

## Performance Optimization

### Batch Balance Queries

Query multiple balances efficiently:

```javascript
async function batchGetBalances(addresses) {
  const batch = addresses.map((addr, i) => ({
    jsonrpc: '2.0',
    method: 'eth_getBalance',
    params: [addr, 'latest'],
    id: i
  }));
  
  const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(batch)
  });
  
  const results = await response.json();
  return results.map((r, i) => ({
    address: addresses[i],
    balance: formatEther(BigInt(r.result))
  }));
}
```

### Caching Strategy

Implement smart caching for balance queries:

```javascript
class BalanceCache {
  constructor(ttl = 5000) {
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  getCacheKey(address, block) {
    return `${address}-${block}`;
  }
  
  async getBalance(provider, address, block = 'latest') {
    const key = this.getCacheKey(address, block);
    const cached = this.cache.get(key);
    
    // Return cached if block is not 'latest' (immutable)
    if (cached && block !== 'latest') {
      return cached.balance;
    }
    
    // Check TTL for 'latest' block
    if (cached && block === 'latest') {
      if (Date.now() - cached.timestamp < this.ttl) {
        return cached.balance;
      }
    }
    
    // Fetch fresh balance
    const balance = await provider.getBalance(address, block);
    this.cache.set(key, {
      balance,
      timestamp: Date.now()
    });
    
    return balance;
  }
}
```

---

## eth_getBlockByHash - Get block Info by hash...

# eth_getBlockByHash - Get block Info by hash...

Retrieves comprehensive information about a block on Neuroweb Mainnet by its hash identifier, including header data, transaction lists, and execution metrics.

## Request Parameters

- `blockHash` (`string, required`): The 32-byte block hash (66 characters with 0x prefix)
- `fullTransactionObjects` (`boolean, required`): When `true`, returns complete transaction objects. When `false`, returns only transaction hashes

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_getBlockByHash",
        "params": [
          "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
          false
        ],
        "id": 1
      }'
```

## Response Fields

- `number` (`string, required`): Block number in hexadecimal
- `hash` (`string, required`): 32-byte block hash
- `parentHash` (`string, required`): Hash of the parent block
- `nonce` (`string, required`): Proof-of-work nonce (always 0x0000000000000000 on Neuroweb Mainnet)
- `sha3Uncles` (`string, required`): SHA3 hash of uncles data
- `logsBloom` (`string, required`): 256-byte bloom filter for block logs
- `transactionsRoot` (`string, required`): Root hash of the transaction trie
- `stateRoot` (`string, required`): Root hash of the final state trie
- `receiptsRoot` (`string, required`): Root hash of the receipts trie
- `miner` (`string, required`): Address receiving block rewards
- `difficulty` (`string, required`): Block difficulty (always 0x0 on Neuroweb Mainnet)
- `totalDifficulty` (`string, required`): Total chain difficulty up to this block
- `extraData` (`string, required`): Additional block-specific data
- `size` (`string, required`): Block size in bytes (hexadecimal)
- `gasLimit` (`string, required`): Maximum gas allowed in block
- `gasUsed` (`string, required`): Total gas consumed by all transactions
- `timestamp` (`string, required`): Unix timestamp of block creation
- `transactions` (`array, required`): Array of transaction hashes or full transaction objects
- `uncles` (`array, required`): Array of uncle block hashes (always empty on Neuroweb Mainnet)
- `baseFeePerGas` (`string, required`): Base fee per gas unit (EIP-1559)
- `withdrawals` (`array, required`): Validator withdrawals (if applicable)
- `withdrawalsRoot` (`string, required`): Root hash of withdrawals trie

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "baseFeePerGas": "0x2da282a8",
    "difficulty": "0x0",
    "extraData": "0x",
    "gasLimit": "0x1c9c380",
    "gasUsed": "0x3b9aca",
    "hash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    "logsBloom": "0x00000000000000000000000000000000...",
    "miner": "0x0000000000000000000000000000000000000000",
    "nonce": "0x0000000000000000",
    "number": "0x5bad55",
    "parentHash": "0xb4fbadf8ea452b139718e2700dc1135cfc81145031c84b7ab27cd99f43ec28ca",
    "receiptsRoot": "0x9b0816dba2e4c1c7b2d38d0c3da6e6bb93c1713a7e986e38f856b6fb725234cf",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "size": "0x21d",
    "stateRoot": "0xddc8b0234248b014296fed29c5c0e9d6e5a6e4a0576ce66970a36c064e3cd96b",
    "timestamp": "0x5e0be0ff",
    "totalDifficulty": "0x0",
    "transactions": [
      "0x5d2dd8b32dc30f347120c5877975c93ccf3e5a5c9ad0c595b0a73c3e00c9e9bb",
      "0x8a91b1b37e0e463c27cb340dc0e2cbc5636cba8d9b3e9a66c2a9e6c3f8c65e82"
    ],
    "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
    "uncles": []
  }
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
      false
    ],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getBlockByHash',
    params: [
      '0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd',
      false  // Set to true for full transaction objects
    ],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

```python
import requests
import json

url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}

payload = {
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
        "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
        False  # Set to True for full transaction objects
    ],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
print(response.json()['result'])
```

---

## eth_getBlockByNumber - Get Block Details

# eth_getBlockByNumber - Get Block Details

Returns information about a block by block number on Neuroweb Mainnet.

## When to Use This Method

`eth_getBlockByNumber` is crucial for:

- **Block Explorers** - Display block information and transactions
- **Chain Analytics** - Analyze block patterns and metrics
- **Transaction Verification** - Confirm transaction inclusion
- **DApp Synchronization** - Process blocks sequentially

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number, null if pending
- `hash` (``DATA`, 32 bytes, required`): Block hash, null if pending
- `parentHash` (``DATA`, 32 bytes, required`): Parent block hash
- `nonce` (``DATA`, 8 bytes, required`): Proof-of-work nonce (always 0 on Ethereum)
- `sha3Uncles` (``DATA`, 32 bytes, required`): SHA3 of uncles (always empty on Ethereum)
- `logsBloom` (``DATA`, 256 bytes, required`): Bloom filter for logs
- `transactionsRoot` (``DATA`, 32 bytes, required`): Root of transaction trie
- `stateRoot` (``DATA`, 32 bytes, required`): Root of final state trie
- `receiptsRoot` (``DATA`, 32 bytes, required`): Root of receipts trie
- `miner` (``DATA`, 20 bytes, required`): Beneficiary address (sequencer on Ethereum)
- `difficulty` (`QUANTITY, required`): Difficulty (always 0 on Ethereum)
- `totalDifficulty` (`QUANTITY, required`): Total difficulty
- `extraData` (`DATA, required`): Extra data field
- `size` (`QUANTITY, required`): Block size in bytes
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed
- `gasUsed` (`QUANTITY, required`): Total gas used by transactions
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `transactions` (`Array, required`): Transaction objects or hashes
- `uncles` (`Array, required`): Uncle hashes (always empty on Ethereum)
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)
- `l1BlockNumber` (`QUANTITY, required`): Corresponding L1 block (Neuroweb specific)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "baseFeePerGas": "0x3e",
    "difficulty": "0x0",
    "extraData": "0x",
    "gasLimit": "0x1c9c380",
    "gasUsed": "0x4f916",
    "hash": "0x1234567890abcdef...",
    "logsBloom": "0x00000000...",
    "miner": "0x0000000000000000000000000000000000000000",
    "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "nonce": "0x0000000000000000",
    "number": "0x5bad55",
    "parentHash": "0xabcdef1234567890...",
    "receiptsRoot": "0x...",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "size": "0x4d6",
    "stateRoot": "0x...",
    "timestamp": "0x64f1b438",
    "totalDifficulty": "0x0",
    "transactions": [
      "0xhash1...",
      "0xhash2...",
      "0xhash3..."
    ],
    "transactionsRoot": "0x...",
    "uncles": []
  }
}
```

## Error Responses

### Error 1

- Code: `-32602`
- Description: Invalid block number

### Error 2

- Code: `-32000`
- Description: Block not found

### Error 3

- Code: `-32005`
- Description: Rate limit exceeded

## Implementation Examples

cURL
JavaScript
Python
Go

```bash
# Get block with transaction hashes only
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'

# Get block with full transaction details
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["0x5BAD55", true],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY');

// Get latest block with transactions
async function getLatestBlock() {
  const block = await provider.getBlock('latest', true);
  
  console.log('Block Number:', block.number);
  console.log('Block Hash:', block.hash);
  console.log('Timestamp:', new Date(block.timestamp * 1000));
  console.log('Transactions:', block.transactions.length);
  console.log('Gas Used:', block.gasUsed.toString());
  console.log('Neuroweb Fee:', block.baseFeePerGas?.toString());
  
  return block;
}

// Get block range
async function getBlockRange(start, end) {
  const blocks = [];
  
  for (let i = start; i <= end; i++) {
    const block = await provider.getBlock(i);
    blocks.push({
      number: block.number,
      timestamp: block.timestamp,
      transactions: block.transactions.length,
      gasUsed: block.gasUsed.toString()
    });
  }
  
  return blocks;
}

// Analyze block statistics
async function analyzeBlock(blockNumber) {
  const block = await provider.getBlock(blockNumber, true);
  
  const analysis = {
    number: block.number,
    timestamp: new Date(block.timestamp * 1000),
    transactionCount: block.transactions.length,
    gasUsed: block.gasUsed,
    gasLimit: block.gasLimit,
    utilization: (Number(block.gasUsed) / Number(block.gasLimit) * 100).toFixed(2) + '%',
    baseFee: block.baseFeePerGas,
    totalValue: block.transactions.reduce((sum, tx) => sum + BigInt(tx.value || 0), 0n)
  };
  
  return analysis;
}
```

```python
from web3 import Web3
from datetime import datetime

w3 = Web3(Web3.HTTPProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'))

def get_block_details(block_identifier='latest', full_transactions=False):
    """Get block with optional full transaction details"""
    block = w3.eth.get_block(block_identifier, full_transactions)
    
    return {
        'number': block['number'],
        'hash': block['hash'].hex(),
        'timestamp': datetime.fromtimestamp(block['timestamp']),
        'transactions': len(block['transactions']),
        'gas_used': block['gasUsed'],
        'gas_limit': block['gasLimit'],
        'base_fee': block.get('baseFeePerGas', 0)
    }

def analyze_blocks(start_block, num_blocks=10):
    """Analyze multiple blocks for patterns"""
    blocks_data = []
    
    for i in range(num_blocks):
        block_num = start_block + i
        block = w3.eth.get_block(block_num)
        
        blocks_data.append({
            'number': block_num,
            'timestamp': block['timestamp'],
            'tx_count': len(block['transactions']),
            'gas_used': block['gasUsed'],
            'block_time': block['timestamp'] - blocks_data[-1]['timestamp'] 
                        if blocks_data else 0
        })
    
    # Calculate averages
    avg_tx = sum(b['tx_count'] for b in blocks_data) / len(blocks_data)
    avg_gas = sum(b['gas_used'] for b in blocks_data) / len(blocks_data)
    avg_time = sum(b['block_time'] for b in blocks_data[1:]) / (len(blocks_data) - 1)
    
    return {
        'blocks': blocks_data,
        'averages': {
            'transactions_per_block': avg_tx,
            'gas_per_block': avg_gas,
            'block_time': avg_time
        }
    }
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"
    
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }
    
    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Block Number: %s\n", block.Number().String())
    fmt.Printf("Block Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Block Time: %s\n", time.Unix(int64(block.Time()), 0))
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
    fmt.Printf("Gas Used: %d\n", block.GasUsed())
    
    // Get specific block
    blockNumber := big.NewInt(1000000)
    historicalBlock, err := client.BlockByNumber(context.Background(), blockNumber)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Historical Block: %s\n", historicalBlock.Number().String())
}
```

## Common Use Cases

### 1. Block Explorer Display

```javascript
async function formatBlockForExplorer(blockNumber) {
  const block = await provider.getBlock(blockNumber, true);
  
  return {
    number: block.number,
    hash: block.hash,
    timestamp: new Date(block.timestamp * 1000).toISOString(),
    miner: block.miner,
    transactionCount: block.transactions.length,
    gasUsed: `${(Number(block.gasUsed) / 1e6).toFixed(2)}M`,
    gasLimit: `${(Number(block.gasLimit) / 1e6).toFixed(2)}M`,
    utilization: `${(Number(block.gasUsed) / Number(block.gasLimit) * 100).toFixed(2)}%`,
    baseFee: `${Number(block.baseFeePerGas) / 1e9} Gwei`,
    burnt: formatEther(block.gasUsed * block.baseFeePerGas)
  };
}
```

### 2. Transaction Confirmation

```javascript
async function confirmTransaction(txHash, confirmations = 6) {
  const tx = await provider.getTransaction(txHash);
  if (!tx) throw new Error('Transaction not found');
  
  const receipt = await provider.getTransactionReceipt(txHash);
  if (!receipt) {
    console.log('Transaction pending...');
    return false;
  }
  
  const currentBlock = await provider.getBlockNumber();
  const confirmCount = currentBlock - receipt.blockNumber + 1;
  
  if (confirmCount >= confirmations) {
    const block = await provider.getBlock(receipt.blockNumber, true);
    const txInBlock = block.transactions.find(t => t.hash === txHash);
    
    return {
      confirmed: true,
      confirmations: confirmCount,
      block: receipt.blockNumber,
      timestamp: block.timestamp,
      position: txInBlock ? block.transactions.indexOf(txInBlock) : -1
    };
  }
  
  return {
    confirmed: false,
    confirmations: confirmCount,
    needed: confirmations - confirmCount
  };
}
```

### 3. Block Time Analysis

```javascript
async function analyzeBlockTimes(count = 100) {
  const latest = await provider.getBlockNumber();
  const blocks = [];
  
  for (let i = 0; i < count; i++) {
    const block = await provider.getBlock(latest - i);
    blocks.push({
      number: block.number,
      timestamp: block.timestamp
    });
  }
  
  const blockTimes = [];
  for (let i = 1; i < blocks.length; i++) {
    blockTimes.push(blocks[i-1].timestamp - blocks[i].timestamp);
  }
  
  return {
    average: blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length,
    min: Math.min(...blockTimes),
    max: Math.max(...blockTimes),
    blocks: blockTimes
  };
}
```

### 4. Gas Price Tracking

```javascript
async function trackGasPrices(blocks = 10) {
  const latest = await provider.getBlockNumber();
  const gasPrices = [];
  
  for (let i = 0; i < blocks; i++) {
    const block = await provider.getBlock(latest - i, true);
    
    // Calculate effective gas prices from transactions
    const prices = block.transactions
      .filter(tx => tx.gasPrice || tx.maxFeePerGas)
      .map(tx => {
        if (tx.type === 2) { // EIP-1559
          return BigInt(tx.maxFeePerGas) < BigInt(block.baseFeePerGas) + BigInt(tx.maxPriorityFeePerGas)
            ? BigInt(tx.maxFeePerGas)
            : BigInt(block.baseFeePerGas) + BigInt(tx.maxPriorityFeePerGas);
        }
        return BigInt(tx.gasPrice);
      });
    
    if (prices.length > 0) {
      const avgPrice = prices.reduce((a, b) => a + b, 0n) / BigInt(prices.length);
      gasPrices.push({
        block: block.number,
        baseFee: Number(block.baseFeePerGas) / 1e9,
        avgPrice: Number(avgPrice) / 1e9,
        txCount: block.transactions.length
      });
    }
  }
  
  return gasPrices;
}
```

## Performance Optimization

### Parallel Block Fetching

```javascript
async function getBlocksParallel(startBlock, count) {
  const promises = [];
  
  for (let i = 0; i < count; i++) {
    promises.push(provider.getBlock(startBlock + i));
  }
  
  const blocks = await Promise.all(promises);
  return blocks;
}
```

### Block Caching

```javascript
class BlockCache {
  constructor(maxSize = 100) {
    this.cache = new Map();
    this.maxSize = maxSize;
  }
  
  async getBlock(provider, blockNumber, fullTx = false) {
    const key = `${blockNumber}-${fullTx}`;
    
    if (this.cache.has(key)) {
      return this.cache.get(key);
    }
    
    const block = await provider.getBlock(blockNumber, fullTx);
    
    // LRU eviction
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    
    this.cache.set(key, block);
    return block;
  }
}
```

---

## eth_getCode - Get Neuroweb Contract Bytecode

# eth_getCode - Get Neuroweb Contract Bytecode

Retrieves the compiled bytecode of a smart contract deployed on the Neuroweb network. This method is essential for contract verification, security analysis, and understanding deployed contract functionality on Ethereum's Layer 2 infrastructure.

## Request Parameters

- `address` (`string, required`): The 20-byte address of the contract (0x-prefixed hex string)
- `blockNumber/blockTag` (`string, required`): Block number in hex (e.g., "0x1b4") or block tag: "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "<address>",
    "<blockNumber/blockTag>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`string, required`): Hex-encoded bytecode starting with "0x". Returns "0x" for EOA addresses

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x608060405234801561001057600080fd5b50600436106101735760003560e01c80638da5cb5b116100de578063c87b56dd11610097578063e985e9c511610071578063e985e9c5146104a2578063f2fde38b146104de578063f46a04eb146104fa578063f5298aca1461051657610173565b8063c87b56dd1461044a578063d547741f14610466578063e8a3d4851461048257610173565b80638da5cb5b146103a657806391d14854146103c457806395d89b41146103e0578063a217fddf146103fe578063a22cb4651461041c578063bd85b0391461043857610173565b80632f2ff15d1161013057806336568abe1161010a57806336568abe146103285780634e1273f414610344578063715018a6146103745780638456cb591461037e57610173565b80632f2ff15d146102cc5780633659cfe6146102e85780633f4ba83a1461030457610173565b8062fdd58e1461017857806301ffc9a71461019857806306fdde03146101c85780630e89341c146101e6578063248a9ca3146102065780632eb2c2d614610236575b600080fd5b610182600480360381019061017d9190611c3a565b610532565b60405161018f9190611c89565b60405180910390f35b6101b260048036038101906101ad9190611cfc565b6105fa565b60405161..."
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get bytecode for USDC contract on Ethereum
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Get bytecode for Ethereum's official bridge contract
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getCode',
    params: [
      '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      'latest'
    ],
    id: 1
  })
});

const data = await response.json();
console.log('Contract bytecode:', data.result);

// Check if address is a contract or EOA
if (data.result === '0x') {
  console.log('Address is an EOA (no contract code)');
} else {
  console.log('Address contains contract code');
}
```

```python
import requests
import json

# Get bytecode for Coinbase's cbETH contract on Ethereum
url = "https://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
payload = {
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
        "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",  # cbETH on Ethereum
        "latest"
    ],
    "id": 1
}

response = requests.post(url, json=payload)
result = response.json()

if result['result'] == '0x':
    print("Address is an EOA")
else:
    print(f"Contract bytecode: {result['result'][:100]}...")  # First 100 chars
    print(f"Bytecode length: {len(result['result'])} characters")
```

## Important Notes

### EOA vs Contract Addresses

- **Contract addresses**: Return the actual bytecode of the deployed smart contract
- **EOA addresses**: Return "0x" as they contain no contract code
- Use this method to programmatically distinguish between EOAs and contracts

### Use Cases

- **Contract verification**: Compare deployed bytecode with source code
- **Security analysis**: Analyze contract functionality and potential vulnerabilities
- **Proxy detection**: Identify proxy contracts and their implementation patterns
- **Contract interaction**: Understand contract capabilities before interaction

### Ethereum-Specific Considerations

- Neuroweb is the main Layer 1 blockchain using Proof of Stake consensus
- Bytecode format is identical to Neuroweb mainnet
- Gas costs for contract deployment and execution are significantly lower
- Full compatibility with Neuroweb smart contracts and tooling

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Neuroweb documentation](https://www.dwellir.com/docs/neuroweb).*

---

## eth_getFilterChanges - Poll filter for changes

# eth_getFilterChanges - Poll filter for changes

Polling method for a filter, which returns an array of events that have occurred since the last poll on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_getFilterChanges",
        "params": ["0x16"],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `address` (string): Address from which this log originated `topics` (array of strings): Array of 0 to 4 32-byte DATA topics `data` (string): Contains non-indexed arguments of the log `blockNumber` (string): Block number where this log was included `blockHash` (string): Hash of the block where this log was included `transactionHash` (string): Hash of the transaction that created this log `transactionIndex` (string): Transaction index position in the block `logIndex` (string): Integer of the log index position in the block `removed` (boolean): true when the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
      "blockNumber": "0x1b4",
      "blockHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "transactionHash": "0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
      "transactionIndex": "0x1",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x16"],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getFilterChanges',
    params: ['0x16'],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

```python
import requests
import json

url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}
payload = {
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x16"],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
data = response.json()
print(data['result'])
```

## Notes

- This method only returns changes that occurred since the last poll
- Filters timeout if not accessed within a certain time period (typically 5 minutes)
- The first call to eth\_getFilterChanges returns all events since filter creation
- Subsequent calls return only new events since the previous call
- Use eth\_getFilterLogs to retrieve all accumulated logs regardless of polling

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Neuroweb documentation](https://www.dwellir.com/docs/neuroweb).*

---

## eth_getFilterLogs - Get Filter Logs

# eth_getFilterLogs - Get Filter Logs

Returns an array of all logs matching filter with given id on the Neuroweb network. This method retrieves all accumulated logs that match the criteria of a previously created filter.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_getFilterLogs",
        "params": ["0x16"],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `address` (string): Address from which this log originated `topics` (array of strings): Array of 0 to 4 32-byte DATA topics. The first topic is the hash of the signature of the event `data` (string): Contains non-indexed arguments of the log `blockNumber` (string): Block number where this log was included (null when pending) `blockHash` (string): Hash of the block where this log was included (null when pending) `transactionHash` (string): Hash of the transaction that created this log (null when pending) `transactionIndex` (string): Transaction index position in the block (null when pending) `logIndex` (string): Integer of the log index position in the block (null when pending) `removed` (boolean): true when the log was removed due to a chain reorganization, false if it's a valid log

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000009876543210fedcba9876543210fedcba98765432"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
      "blockNumber": "0x1b4",
      "blockHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "transactionHash": "0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
      "transactionIndex": "0x1",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterLogs",
    "params": ["0x16"],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getFilterLogs',
    params: ['0x16'],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

```python
import requests
import json

url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}
payload = {
    "jsonrpc": "2.0",
    "method": "eth_getFilterLogs",
    "params": ["0x16"],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
data = response.json()
print(data['result'])
```

## Notes

- The filter must be created first using `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`
- This method returns all logs accumulated since the filter was created
- Filters timeout if not accessed within a certain time period (typically 5 minutes)
- Use `eth_getFilterChanges` to get only new logs since the last poll
- The `removed` field helps handle chain reorganizations

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Neuroweb documentation](https://www.dwellir.com/docs/neuroweb).*

---

## eth_getLogs - Query Event Logs

# eth_getLogs - Query Event Logs

Returns an array of all logs matching a given filter object. Essential for querying historical events and monitoring smart contract activity.

## Block Range Limits

| Plan            | Maximum blocks per request |
| --------------- | -------------------------: |
| Free            |              Not available |
| Developer       |                        500 |
| Growth          |                     10,000 |
| Scale and above |                     10,000 |

Both endpoints count toward the limit: `toBlock - fromBlock + 1`.
Supply explicit numeric bounds for historical ranges, or use `blockHash` for one block.
Split longer ranges into requests within your plan limit.
See [request rules and errors](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits), including accepted block tags.

## When to Use This Method

`eth_getLogs` is crucial for:

- **Event Monitoring** - Track smart contract events and state changes
- **Historical Queries** - Search past events within a block range
- **DeFi Analytics** - Monitor trades, liquidity events, and protocol activity
- **Indexing** - Build databases of on-chain events

## Request Parameters

- `filter` (`OBJECT, required`): Supply block bounds, or blockHash for one block. Missing or null bounds default to latest. See the block range limits above.
- `filter.fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to latest.
- `filter.toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to latest.
- `filter.blockHash` (`DATA, optional`): A 32-byte block hash. Cannot be combined with non-null fromBlock or toBlock.
- `filter.address` (`DATA|Array, optional`): Contract address or array of contract addresses.
- `filter.topics` (`Array, optional`): Indexed event filters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{"fromBlock": "0x1", "toBlock": "0x1f4"}],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): `removed` - `true` if log was removed due to reorg `logIndex` - Position in the block `transactionIndex` - Transaction position in block `transactionHash` - Hash of transaction `blockHash` - Hash of block `blockNumber` - Block number `address` - Contract address `data` - Non-indexed log parameters `topics` - Array of indexed log parameters

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7d8d9ef8d8ce8992df33d8b8cf4aebabd5bd270",
        "0x0000000000000000000000004e6b5f1abfb9aa3cc5b3d8f4a7b8c2d9e3f0a1b2"
      ],
      "data": "0x000000000000000000000000000000000000000000000000016345785d8a0000",
      "blockNumber": "0x123abc",
      "blockHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      "transactionHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "transactionIndex": "0x0",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Block range exceeds plan limit

- Code: `-32005`
- Description: HTTP 200 with a JSON-RPC error. Split the range into requests within your plan limit.

### Invalid block range

- Code: `-32602`
- Description: HTTP 200 with a JSON-RPC error. Supply valid bounds or a blockHash without non-null bounds.

### Chain head unavailable

- Code: `-32000`
- Description: HTTP 200 with a JSON-RPC error. Retry shortly or use explicit hexadecimal bounds.

### Error 1

- Description: Too many logs in range

### Error 2

- Description: fromBlock > toBlock

### Error 3

- Description: Large query timeout

## Implementation Examples

The helpers below take a numeric starting height and a numeric ending height or `latest`.
They resolve `latest` once and split historical ranges into 500-block requests.
The JavaScript examples use `toQuantity` to encode block heights without leading zeroes.

curl
JavaScript
Python

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "0x1",
      "toBlock": "latest",
      "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
      ]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface, id, zeroPadValue, toQuantity } from 'ethers';

const provider = new JsonRpcProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY');

// Advanced event monitoring system
class EventMonitor {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async getTransferEvents(tokenAddress, fromBlock, toBlock) {
    // ERC20 Transfer event signature
    const transferTopic = id('Transfer(address,address,uint256)');
    
    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: tokenAddress,
      topics: [transferTopic]
    };

    const logs = await this.getPaginatedLogs(filter);
    
    // Decode logs
    const iface = new Interface([
      'event Transfer(address indexed from, address indexed to, uint256 value)'
    ]);

    return logs.map(log => {
      const decoded = iface.parseLog({
        topics: log.topics,
        data: log.data
      });

      return {
        from: decoded.args.from,
        to: decoded.args.to,
        value: decoded.args.value.toString(),
        blockNumber: log.blockNumber,
        transactionHash: log.transactionHash,
        logIndex: log.logIndex
      };
    });
  }

  async getEventsBySignature(signature, address, fromBlock, toBlock) {
    const eventTopic = id(signature);
    
    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: address,
      topics: [eventTopic]
    };

    return await this.getPaginatedLogs(filter);
  }

  async queryWithMultipleAddresses(addresses, eventSignature, fromBlock, toBlock) {
    const eventTopic = id(eventSignature);
    
    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: addresses, // Array of addresses
      topics: [eventTopic]
    };

    const logs = await this.getPaginatedLogs(filter);
    
    // Group by address
    const grouped = {};
    for (const log of logs) {
      if (!grouped[log.address]) {
        grouped[log.address] = [];
      }
      grouped[log.address].push(log);
    }
    
    return grouped;
  }

  async getFilteredTransfers(tokenAddress, specificAddress, direction, fromBlock, toBlock) {
    const transferTopic = id('Transfer(address,address,uint256)');
    
    let topics;
    if (direction === 'from') {
      // Transfers FROM specific address
      topics = [
        transferTopic,
        zeroPadValue(specificAddress, 32),
        null
      ];
    } else if (direction === 'to') {
      // Transfers TO specific address
      topics = [
        transferTopic,
        null,
        zeroPadValue(specificAddress, 32)
      ];
    } else {
      // All transfers involving address
      const [fromLogs, toLogs] = await Promise.all([
        this.getFilteredTransfers(tokenAddress, specificAddress, 'from', fromBlock, toBlock),
        this.getFilteredTransfers(tokenAddress, specificAddress, 'to', fromBlock, toBlock)
      ]);
      return [...fromLogs, ...toLogs].sort((a, b) => a.blockNumber - b.blockNumber);
    }

    const filter = {
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: tokenAddress,
      topics: topics
    };

    return await this.getPaginatedLogs(filter);
  }

  async searchDeFiEvents(protocolAddress, fromBlock, toBlock) {
    // Common DeFi event signatures
    const eventSignatures = {
      swap: 'Swap(address,uint256,uint256,uint256,uint256,address)',
      addLiquidity: 'Mint(address,uint256,uint256)',
      removeLiquidity: 'Burn(address,uint256,uint256,address)',
      deposit: 'Deposit(address,uint256,uint256)',
      withdraw: 'Withdrawal(address,uint256,uint256)',
      borrow: 'Borrow(address,address,uint256,uint256,uint256)',
      repay: 'Repay(address,address,uint256,uint256)'
    };

    const events = {};
    
    for (const [name, signature] of Object.entries(eventSignatures)) {
      try {
        const logs = await this.getEventsBySignature(
          signature,
          protocolAddress,
          fromBlock,
          toBlock
        );
        
        if (logs.length > 0) {
          events[name] = logs;
        }
      } catch (error) {
        // Event might not exist in this contract
        continue;
      }
    }
    
    return events;
  }

  async getPaginatedLogs(filter, pageSize = 500) {
    const results = [];
    let currentBlock = parseInt(filter.fromBlock);
    const endBlock = filter.toBlock === 'latest' ? 
      await this.provider.getBlockNumber() : 
      parseInt(filter.toBlock);
    
    while (currentBlock <= endBlock) {
      const chunkEnd = Math.min(currentBlock + pageSize - 1, endBlock);
      
      const chunkFilter = {
        ...filter,
        fromBlock: toQuantity(currentBlock),
        toBlock: toQuantity(chunkEnd)
      };
      
      try {
        const logs = await this.provider.getLogs(chunkFilter);
        results.push(...logs);
        
        console.log(`Fetched blocks ${currentBlock} to ${chunkEnd}: ${logs.length} logs`);
      } catch (error) {
        if (error.message.includes('query returned more than')) {
          // Reduce page size and retry
          return this.getPaginatedLogs(filter, Math.floor(pageSize / 2));
        }
        throw error;
      }
      
      currentBlock = chunkEnd + 1;
    }
    
    return results;
  }

  createLiveEventStream(filter, callback) {
    const processNewBlock = async (blockNumber) => {
      const logs = await this.getPaginatedLogs({
        ...filter,
        fromBlock: toQuantity(blockNumber),
        toBlock: toQuantity(blockNumber)
      });
      
      if (logs.length > 0) {
        callback(logs);
      }
    };
    
    // Listen for new blocks
    this.provider.on('block', processNewBlock);
    
    // Return unsubscribe function
    return () => {
      this.provider.off('block', processNewBlock);
    };
  }
}

// NFT event monitoring
class NFTEventTracker extends EventMonitor {

  async getERC721Transfers(contractAddress, fromBlock, toBlock) {
    const transferTopic = id('Transfer(address,address,uint256)');
    
    const logs = await this.getPaginatedLogs({
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: contractAddress,
      topics: [transferTopic]
    });

    const iface = new Interface([
      'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)'
    ]);

    return logs.map(log => {
      const decoded = iface.parseLog({
        topics: log.topics,
        data: log.data
      });

      return {
        from: decoded.args.from,
        to: decoded.args.to,
        tokenId: decoded.args.tokenId.toString(),
        blockNumber: log.blockNumber,
        transactionHash: log.transactionHash,
        isMint: decoded.args.from === '0x0000000000000000000000000000000000000000',
        isBurn: decoded.args.to === '0x0000000000000000000000000000000000000000'
      };
    });
  }

  async getERC1155Transfers(contractAddress, fromBlock, toBlock) {
    const singleTransferTopic = id('TransferSingle(address,address,address,uint256,uint256)');
    const batchTransferTopic = id('TransferBatch(address,address,address,uint256[],uint256[])');
    
    const [singleLogs, batchLogs] = await Promise.all([
      this.getPaginatedLogs({
        fromBlock: toQuantity(fromBlock),
        toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
        address: contractAddress,
        topics: [singleTransferTopic]
      }),
      this.getPaginatedLogs({
        fromBlock: toQuantity(fromBlock),
        toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
        address: contractAddress,
        topics: [batchTransferTopic]
      })
    ]);
    
    return {
      single: singleLogs,
      batch: batchLogs,
      total: singleLogs.length + batchLogs.length
    };
  }
}

// Usage examples
const monitor = new EventMonitor(provider);

// Get transfer events for a token
const transfers = await monitor.getTransferEvents(
  '0xTokenAddress',
  12345678,
  'latest'
);

// Monitor specific address activity
const userTransfers = await monitor.getFilteredTransfers(
  '0xTokenAddress',
  '0xUserAddress',
  'both', // 'from', 'to', or 'both'
  12345678,
  'latest'
);

// Search DeFi protocol events
const defiEvents = await monitor.searchDeFiEvents(
  '0xProtocolAddress',
  12345678,
  12345778
);

// Create live event stream
const unsubscribe = monitor.createLiveEventStream(
  {
    address: '0xTokenAddress',
    topics: [id('Transfer(address,address,uint256)')]
  },
  (logs) => {
    console.log('New events:', logs);
  }
);
```

```python
from web3 import Web3
from eth_utils import event_signature_to_log_topic, to_hex
import json
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta

w3 = Web3(Web3.HTTPProvider('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'))

class LogAnalyzer:
    """Analyze and query event logs on Neuroweb Mainnet"""
    
    def __init__(self, w3_instance):
        self.w3 = w3_instance
    
    def get_transfer_events(
        self,
        token_address: str,
        from_block: int,
        to_block: str = 'latest',
        from_address: Optional[str] = None,
        to_address: Optional[str] = None
    ) -> List[Dict[str, Any]]:
        """Get ERC20 transfer events with optional filtering"""
        
        # Transfer event signature
        transfer_topic = self.w3.keccak(text='Transfer(address,address,uint256)').hex()
        
        # Build topics array
        topics = [transfer_topic]
        
        if from_address:
            topics.append(self._address_to_topic(from_address))
        else:
            topics.append(None)
        
        if to_address:
            topics.append(self._address_to_topic(to_address))
        
        # Create filter
        filter_params = {
            'fromBlock': from_block,
            'toBlock': to_block,
            'address': token_address,
            'topics': topics
        }
        
        # Get logs
        logs = self.get_logs_paginated(filter_params)
        
        # Decode logs
        transfers = []
        for log in logs:
            transfers.append({
                'from': self._topic_to_address(log['topics'][1]),
                'to': self._topic_to_address(log['topics'][2]),
                'value': int(log['data'], 16) if log['data'] != '0x' else 0,
                'block_number': log['blockNumber'],
                'transaction_hash': log['transactionHash'].hex(),
                'log_index': log['logIndex'],
                'address': log['address']
            })
        
        return transfers
    
    def _address_to_topic(self, address: str) -> str:
        """Convert address to topic format"""
        return '0x' + address[2:].lower().zfill(64)
    
    def _topic_to_address(self, topic: str) -> str:
        """Convert topic to address format"""
        return '0x' + topic.hex()[-40:]
    
    def get_events_by_signature(
        self,
        event_signature: str,
        contract_address: Optional[str] = None,
        from_block: int = 0,
        to_block: str = 'latest'
    ) -> List[Dict[str, Any]]:
        """Get events by signature"""
        
        event_topic = self.w3.keccak(text=event_signature).hex()
        
        filter_params = {
            'fromBlock': from_block,
            'toBlock': to_block,
            'topics': [event_topic]
        }
        
        if contract_address:
            filter_params['address'] = contract_address
        
        logs = self.get_logs_paginated(filter_params)
        
        return [{
            'address': log['address'],
            'topics': [t.hex() for t in log['topics']],
            'data': log['data'],
            'block_number': log['blockNumber'],
            'transaction_hash': log['transactionHash'].hex(),
            'log_index': log['logIndex']
        } for log in logs]
    
    def search_defi_activity(
        self,
        protocol_address: str,
        from_block: int,
        to_block: str = 'latest'
    ) -> Dict[str, List[Dict]]:
        """Search for common DeFi events"""
        
        event_signatures = {
            'swaps': 'Swap(address,uint256,uint256,uint256,uint256,address)',
            'liquidity_added': 'Mint(address,uint256,uint256)',
            'liquidity_removed': 'Burn(address,uint256,uint256,address)',
            'deposits': 'Deposit(address,uint256)',
            'withdrawals': 'Withdrawal(address,uint256)',
            'borrows': 'Borrow(address,address,uint256,uint256,uint256)',
            'repayments': 'Repay(address,address,uint256,uint256)'
        }
        
        results = {}
        
        for event_type, signature in event_signatures.items():
            try:
                logs = self.get_events_by_signature(
                    signature,
                    protocol_address,
                    from_block,
                    to_block
                )
                
                if logs:
                    results[event_type] = logs
            except Exception as e:
                # Event might not exist in this contract
                continue
        
        return results
    
    def get_nft_transfers(
        self,
        nft_address: str,
        from_block: int,
        to_block: str = 'latest',
        token_id: Optional[int] = None
    ) -> List[Dict[str, Any]]:
        """Get NFT transfer events (ERC721)"""
        
        # Transfer event with tokenId as indexed parameter
        transfer_topic = self.w3.keccak(text='Transfer(address,address,uint256)').hex()
        
        topics = [transfer_topic, None, None]
        
        if token_id is not None:
            topics.append(to_hex(token_id).zfill(66))
        
        filter_params = {
            'fromBlock': from_block,
            'toBlock': to_block,
            'address': nft_address,
            'topics': topics
        }
        
        logs = self.get_logs_paginated(filter_params)
        
        transfers = []
        for log in logs:
            from_addr = self._topic_to_address(log['topics'][1])
            to_addr = self._topic_to_address(log['topics'][2])
            
            transfers.append({
                'from': from_addr,
                'to': to_addr,
                'token_id': int(log['topics'][3].hex(), 16) if len(log['topics']) > 3 else int(log['data'], 16),
                'is_mint': from_addr == '0x0000000000000000000000000000000000000000',
                'is_burn': to_addr == '0x0000000000000000000000000000000000000000',
                'block_number': log['blockNumber'],
                'transaction_hash': log['transactionHash'].hex(),
                'log_index': log['logIndex']
            })
        
        return transfers
    
    def get_logs_paginated(
        self,
        filter_params: Dict,
        page_size: int = 500
    ) -> List[Dict[str, Any]]:
        """Get logs with pagination to avoid query limits"""
        
        all_logs = []
        from_block = filter_params['fromBlock']
        to_block = filter_params['toBlock']
        
        if to_block == 'latest':
            to_block = self.w3.eth.block_number
        
        current_block = from_block
        
        while current_block <= to_block:
            chunk_end = min(current_block + page_size - 1, to_block)
            
            chunk_filter = {
                **filter_params,
                'fromBlock': current_block,
                'toBlock': chunk_end
            }
            
            try:
                logs = self.w3.eth.get_logs(chunk_filter)
                all_logs.extend(logs)
                
                print(f"Fetched blocks {current_block} to {chunk_end}: {len(logs)} logs")
                
            except Exception as e:
                if 'query returned more than' in str(e):
                    # Reduce page size and retry
                    if page_size > 10:
                        return self.get_logs_paginated(filter_params, page_size // 2)
                    else:
                        raise Exception("Block range too large even with minimum page size")
                else:
                    raise e
            
            current_block = chunk_end + 1
        
        return all_logs
    
    def analyze_event_patterns(
        self,
        logs: List[Dict]
    ) -> Dict[str, Any]:
        """Analyze patterns in event logs"""
        
        if not logs:
            return {'error': 'No logs to analyze'}
        
        # Group by block
        blocks = {}
        for log in logs:
            block = log['blockNumber']
            if block not in blocks:
                blocks[block] = []
            blocks[block].append(log)
        
        # Group by transaction
        transactions = {}
        for log in logs:
            tx = log['transactionHash'].hex() if hasattr(log['transactionHash'], 'hex') else log['transactionHash']
            if tx not in transactions:
                transactions[tx] = []
            transactions[tx].append(log)
        
        # Find most active addresses
        addresses = {}
        for log in logs:
            addr = log['address']
            if addr not in addresses:
                addresses[addr] = 0
            addresses[addr] += 1
        
        sorted_addresses = sorted(addresses.items(), key=lambda x: x[1], reverse=True)
        
        return {
            'total_logs': len(logs),
            'unique_blocks': len(blocks),
            'unique_transactions': len(transactions),
            'unique_addresses': len(addresses),
            'most_active_addresses': sorted_addresses[:10],
            'logs_per_block': {
                'average': len(logs) / len(blocks) if blocks else 0,
                'max': max(len(b) for b in blocks.values()) if blocks else 0,
                'min': min(len(b) for b in blocks.values()) if blocks else 0
            },
            'logs_per_transaction': {
                'average': len(logs) / len(transactions) if transactions else 0,
                'max': max(len(t) for t in transactions.values()) if transactions else 0,
                'min': min(len(t) for t in transactions.values()) if transactions else 0
            }
        }
    
    def export_logs_to_csv(
        self,
        logs: List[Dict],
        filename: str
    ):
        """Export logs to CSV file"""
        
        import csv
        
        if not logs:
            return
        
        # Get all unique keys
        keys = set()
        for log in logs:
            keys.update(log.keys())
        
        with open(filename, 'w', newline='') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=sorted(keys))
            writer.writeheader()
            
            for log in logs:
                # Convert bytes to hex strings
                row = {}
                for key, value in log.items():
                    if isinstance(value, bytes):
                        row[key] = value.hex()
                    else:
                        row[key] = value
                writer.writerow(row)
        
        print(f"Exported {len(logs)} logs to {filename}")

# Usage examples
analyzer = LogAnalyzer(w3)

# Get token transfers
transfers = analyzer.get_transfer_events(
    token_address='0xTokenAddress',
    from_block=12345678,
    to_block='latest',
    from_address='0xUserAddress'  # Optional filter
)

print(f"Found {len(transfers)} transfers")
for transfer in transfers[:5]:
    print(f"From: {transfer['from'][:10]}... To: {transfer['to'][:10]}... Value: {transfer['value']}")

# Search DeFi activity
defi_events = analyzer.search_defi_activity(
    protocol_address='0xProtocolAddress',
    from_block=12345678
)

for event_type, events in defi_events.items():
    print(f"{event_type}: {len(events)} events")

# Get NFT transfers
nft_transfers = analyzer.get_nft_transfers(
    nft_address='0xNFTAddress',
    from_block=12345678
)

mints = [t for t in nft_transfers if t['is_mint']]
print(f"Found {len(mints)} NFT mints")

# Analyze event patterns
pattern_analysis = analyzer.analyze_event_patterns(transfers)
print(f"Analysis: {json.dumps(pattern_analysis, indent=2)}")
```

## Advanced Usage

### Multiple Address Filtering

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "0x1",
    "toBlock": "0xc8",
    "address": [
      "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "0x4200000000000000000000000000000000000006"
    ],
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
    ]
  }],
  "id": 1
}
```

### Topic Filtering with OR Logic

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "0x1",
    "toBlock": "0xc8",
    "topics": [
      [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
      ]
    ]
  }],
  "id": 1
}
```

## Notes

- Neuroweb supports **historical log queries** back to genesis block
- **Query limits**: Maximum 10,000 results per request
- **Block range limits**: Developer 500; Growth, Scale, and Enterprise 10,000 blocks per request
- **Topic arrays**: Support up to 4 topics with OR logic within each position
- **Performance tip**: Use specific address filters to improve query speed
- **Event signatures**: First topic is always the keccak256 hash of the event signature

## Common Use Cases

### 1. Token Balance History

```javascript
// Track historical token balance changes
async function getBalanceHistory(tokenAddress, userAddress, fromBlock) {
  const monitor = new EventMonitor(provider);
  
  // Get all transfers involving the user
  const logs = await monitor.getFilteredTransfers(
    tokenAddress,
    userAddress,
    'both',
    fromBlock,
    'latest'
  );
  
  // Calculate balance changes
  const balanceChanges = [];
  let currentBalance = 0n;
  
  for (const log of logs) {
    const iface = new Interface([
      'event Transfer(address indexed from, address indexed to, uint256 value)'
    ]);
    
    const decoded = iface.parseLog({
      topics: log.topics,
      data: log.data
    });
    
    const change = decoded.args.from.toLowerCase() === userAddress.toLowerCase() ?
      -decoded.args.value : decoded.args.value;
    
    currentBalance += change;
    
    balanceChanges.push({
      blockNumber: log.blockNumber,
      transactionHash: log.transactionHash,
      change: change.toString(),
      balance: currentBalance.toString(),
      type: change < 0 ? 'outgoing' : 'incoming'
    });
  }
  
  return balanceChanges;
}
```

### 2. DEX Trade Monitoring

```javascript
// Monitor DEX trading activity
async function monitorDEXTrades(dexAddress, fromBlock) {
  const swapTopic = id('Swap(address,address,int256,int256,uint160,uint128,int24)');
  
  const logs = await new EventMonitor(provider).getPaginatedLogs({
    fromBlock: toQuantity(fromBlock),
    toBlock: 'latest',
    address: dexAddress,
    topics: [swapTopic]
  });
  
  const trades = logs.map(log => {
    // Decode Uniswap V3 swap event
    const iface = new Interface([
      'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)'
    ]);
    
    const decoded = iface.parseLog({
      topics: log.topics,
      data: log.data
    });
    
    return {
      sender: decoded.args.sender,
      recipient: decoded.args.recipient,
      amount0: decoded.args.amount0.toString(),
      amount1: decoded.args.amount1.toString(),
      price: Number(decoded.args.sqrtPriceX96) ** 2 / (2 ** 192),
      blockNumber: log.blockNumber,
      transactionHash: log.transactionHash
    };
  });
  
  return trades;
}
```

### 3. Contract Event Indexer

```javascript
// Build an event index for a contract
class EventIndexer {
  constructor(provider, contractAddress, abi) {
    this.provider = provider;
    this.contractAddress = contractAddress;
    this.iface = new Interface(abi);
    this.eventIndex = new Map();
  }
  
  async indexEvents(fromBlock, toBlock) {
    // Get all events for the contract
    const logs = await new EventMonitor(this.provider).getPaginatedLogs({
      fromBlock: toQuantity(fromBlock),
      toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
      address: this.contractAddress
    });
    
    for (const log of logs) {
      try {
        const parsed = this.iface.parseLog({
          topics: log.topics,
          data: log.data
        });
        
        if (!this.eventIndex.has(parsed.name)) {
          this.eventIndex.set(parsed.name, []);
        }
        
        this.eventIndex.get(parsed.name).push({
          args: Object.fromEntries(
            Object.entries(parsed.args).filter(([key]) => isNaN(key))
          ),
          blockNumber: log.blockNumber,
          transactionHash: log.transactionHash,
          logIndex: log.logIndex
        });
      } catch {
        // Unknown event
      }
    }
    
    return this.getStatistics();
  }
  
  getStatistics() {
    const stats = {};
    
    for (const [eventName, events] of this.eventIndex) {
      stats[eventName] = {
        count: events.length,
        firstBlock: Math.min(...events.map(e => e.blockNumber)),
        lastBlock: Math.max(...events.map(e => e.blockNumber))
      };
    }
    
    return stats;
  }
}
```

---

## eth_getStorageAt - Get Contract Storage Values

# eth_getStorageAt - Get Contract Storage Values

Retrieves the value from a storage position at a given address on the Neuroweb network. This method allows direct access to contract storage slots, enabling you to read contract state variables, proxy implementation addresses, and other stored data.

## Request Parameters

- `address` (`string, required`): The 20-byte address of the contract whose storage you want to read
- `position` (`string, required`): The hex-encoded storage position/slot number (32 bytes)
- `blockNumber` (`string, required`): Block number in hex, or block tag ("latest", "earliest", "pending")

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getStorageAt",
  "params": [
    "<address>",
    "<position>",
    "<blockNumber>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Returns a 32-byte hex string representing the storage value. Values are left-padded with zeros if smaller than 32 bytes.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Read storage slot 0 from USDC contract on Ethereum
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Read storage from Neuroweb USDC contract
const getStorage = async () => {
  const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_getStorageAt',
      params: [
        '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Neuroweb USDC
        '0x0', // Storage slot 0
        'latest'
      ],
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Calculate mapping storage position
const getMappingSlot = (key, slot) => {
  const keyPadded = key.padStart(64, '0');
  const slotPadded = slot.toString(16).padStart(64, '0');
  return web3.utils.keccak256('0x' + keyPadded + slotPadded);
};
```

```python
import requests
from web3 import Web3

# Read storage from contract
def get_storage_at(address, position, block='latest'):
    payload = {
        "jsonrpc": "2.0",
        "method": "eth_getStorageAt",
        "params": [address, position, block],
        "id": 1
    }
    
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json=payload,
        headers={'Content-Type': 'application/json'}
    )
    
    return response.json()['result']

# Example: Read from Neuroweb USDC contract
usdc_address = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
storage_value = get_storage_at(usdc_address, '0x0')

# Calculate mapping storage position
def get_mapping_slot(key, slot):
    key_padded = key.zfill(64)
    slot_padded = hex(slot)[2:].zfill(64)
    return Web3.keccak(bytes.fromhex(key_padded + slot_padded)).hex()

# Example: Get balance mapping for an address
balance_slot = get_mapping_slot('000000000000000000000000YourAddress', 9)
balance = get_storage_at(usdc_address, balance_slot)
```

## Use Cases

- **Contract State Inspection**: Read private or internal variables
- **Proxy Implementation**: Get implementation address from proxy contracts
- **Token Balances**: Access balance mappings directly
- **Access Control**: Check role assignments and permissions
- **Debugging**: Investigate contract state during development

## Important Notes

- Storage values are always 32 bytes (64 hex characters plus 0x prefix)
- Unused storage slots return `0x0000000000000000000000000000000000000000000000000000000000000000`
- Storage layout depends on Solidity version and compiler optimizations
- For dynamic arrays, slot contains length; actual data starts at `keccak256(slot)`
- Packed structs may share storage slots for gas optimization

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Neuroweb documentation](https://www.dwellir.com/docs/neuroweb).*

---

## eth_getTransactionByHash - Get Transaction...

# eth_getTransactionByHash - Get Transaction...

Returns information about a transaction requested by transaction hash. Essential for tracking transaction status and details.

## When to Use This Method

`eth_getTransactionByHash` is crucial for:

- **Transaction Tracking** - Monitor transaction status after submission
- **Payment Verification** - Confirm payment details and recipients
- **Transaction Explorers** - Build transaction detail pages
- **Debugging** - Investigate failed or stuck transactions

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Payment Verification System

```javascript
// Verify payment received
async function verifyPayment(txHash, expectedAmount, expectedRecipient) {
  const tx = await provider.getTransaction(txHash);
  
  if (!tx) {
    return { valid: false, reason: 'Transaction not found' };
  }
  
  // Check recipient
  if (tx.to?.toLowerCase() !== expectedRecipient.toLowerCase()) {
    return { valid: false, reason: 'Wrong recipient' };
  }
  
  // Check amount
  if (tx.value.toString() !== expectedAmount) {
    return { valid: false, reason: 'Wrong amount' };
  }
  
  // Check confirmations
  if (!tx.blockNumber) {
    return { valid: false, reason: 'Transaction pending' };
  }
  
  const receipt = await provider.getTransactionReceipt(txHash);
  if (receipt.status === 0) {
    return { valid: false, reason: 'Transaction failed' };
  }
  
  return {
    valid: true,
    confirmations: tx.confirmations,
    blockNumber: tx.blockNumber
  };
}
```

### 2. Transaction History Builder

```javascript
// Build transaction history for address
async function getAddressTransactions(address, txHashes) {
  const transactions = [];
  
  for (const hash of txHashes) {
    const tx = await provider.getTransaction(hash);
    
    if (!tx) continue;
    
    const isIncoming = tx.to?.toLowerCase() === address.toLowerCase();
    const isOutgoing = tx.from.toLowerCase() === address.toLowerCase();
    
    transactions.push({
      hash: tx.hash,
      type: isIncoming ? 'incoming' : 'outgoing',
      from: tx.from,
      to: tx.to,
      value: ethers.formatEther(tx.value),
      timestamp: tx.blockNumber ? 
        (await provider.getBlock(tx.blockNumber)).timestamp : null,
      status: tx.blockNumber ? 'confirmed' : 'pending',
      gasPrice: tx.gasPrice ? ethers.formatGwei(tx.gasPrice) : null,
      confirmations: tx.confirmations
    });
  }
  
  return transactions.sort((a, b) => b.timestamp - a.timestamp);
}
```

### 3. Gas Price Analysis

```javascript
// Analyze gas usage patterns
async function analyzeGasUsage(txHash) {
  const tx = await provider.getTransaction(txHash);
  
  if (!tx) {
    throw new Error('Transaction not found');
  }
  
  const receipt = await provider.getTransactionReceipt(txHash);
  const block = await provider.getBlock(tx.blockNumber);
  
  return {
    txHash: tx.hash,
    gasLimit: tx.gasLimit.toString(),
    gasUsed: receipt ? receipt.gasUsed.toString() : null,
    gasPrice: tx.gasPrice ? ethers.formatGwei(tx.gasPrice) : null,
    maxFeePerGas: tx.maxFeePerGas ? ethers.formatGwei(tx.maxFeePerGas) : null,
    maxPriorityFee: tx.maxPriorityFeePerGas ? 
      ethers.formatGwei(tx.maxPriorityFeePerGas) : null,
    baseFee: block.baseFeePerGas ? 
      ethers.formatGwei(block.baseFeePerGas) : null,
    efficiency: receipt ? 
      ((Number(receipt.gasUsed) / Number(tx.gasLimit)) * 100).toFixed(2) + '%' : null,
    totalCost: receipt && tx.gasPrice ? 
      ethers.formatEther(receipt.gasUsed * tx.gasPrice) : null
  };
}
```

---

## eth_getTransactionCount - Get Neuroweb Nonce

# eth_getTransactionCount - Get Neuroweb Nonce

Retrieves the number of transactions sent from an account on the Neuroweb network. This method returns the account's nonce, which is essential for transaction ordering and preventing replay attacks. The nonce represents the count of confirmed transactions from the specified address.

## Description

The `eth_getTransactionCount` method is crucial for Neuroweb blockchain interaction as it provides the current transaction count (nonce) for any account. This value must be included in every transaction to ensure proper ordering and prevent duplicate transactions on the Neuroweb Mainnet network.

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: invalid address"
  }
}
```

## Use Cases

- **Transaction Building**: Get next nonce for new transactions
- **Wallet Management**: Track account activity and transaction history
- **Nonce Management**: Prevent transaction conflicts in DApps
- **Account Analysis**: Determine if address is active or new
- **Batch Transactions**: Sequence multiple transactions correctly

## Response Examples

### Latest Block Transaction Count

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c"
}
```

### Pending Transaction Count

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "0x1e"
}
```

## Important Notes

### Nonce Management

- **Transaction Ordering**: Each transaction must use the next sequential nonce
- **Pending vs Confirmed**: Use "pending" to include mempool transactions when building new transactions
- **Failed Transactions**: Failed transactions still consume the nonce and increment the count
- **Nonce Gaps**: Transactions with gaps in nonce sequence will be held until earlier nonces are filled

### Best Practices

- Always use "pending" when preparing new transactions to avoid nonce conflicts
- Cache nonce values briefly but refresh for each new transaction batch
- Handle nonce collisions by incrementing and retrying
- Monitor both confirmed and pending counts for wallet applications

### Neuroweb Network Specifics

- Neuroweb uses a sequential nonce system for transaction ordering
- Transaction finality depends on network confirmation requirements
- Nonce management is crucial for Neuroweb DApp development
- Consider batch transaction sequencing for gas optimization

### Common Use Cases

1. **Wallet Integration**: Track user transaction history
2. **DApp Development**: Sequence contract interactions
3. **Transaction Builders**: Generate properly ordered transactions
4. **Account Analysis**: Determine account activity levels
5. **Automated Systems**: Manage nonce for bot transactions

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Neuroweb documentation](https://www.dwellir.com/docs/neuroweb).*

---

## eth_getTransactionReceipt - Get Receipt

# eth_getTransactionReceipt - Get Receipt

Returns the receipt of a transaction by transaction hash. Provides execution status, gas consumption, and emitted logs.

## When to Use This Method

`eth_getTransactionReceipt` is essential for:

- **Transaction Confirmation** - Verify successful execution
- **Event Monitoring** - Access emitted logs and events
- **Gas Analysis** - Track actual gas consumption
- **Contract Deployment** - Get deployed contract addresses

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x5c884a466fb59ee69114a0c99cb15d4d8af670a37be53fd59ffda3b5566b4269"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Smart Contract Event Monitoring

```javascript
// Monitor DeFi protocol events
async function monitorDeFiEvents(txHash) {
  const DEFI_ABI = [
    "event Deposit(address indexed user, uint256 amount, uint256 shares)",
    "event Withdraw(address indexed user, uint256 amount, uint256 shares)",
    "event Swap(address indexed user, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut)"
  ];
  
  const processor = new ReceiptProcessor(provider);
  const events = await processor.parseEvents(txHash, DEFI_ABI);
  
  for (const event of events) {
    switch(event.name) {
      case 'Deposit':
        console.log(`User ${event.args.user} deposited ${event.args.amount}`);
        break;
      case 'Withdraw':
        console.log(`User ${event.args.user} withdrew ${event.args.amount}`);
        break;
      case 'Swap':
        console.log(`Swap: ${event.args.amountIn} ${event.args.tokenIn} -> ${event.args.amountOut} ${event.args.tokenOut}`);
        break;
    }
  }
  
  return events;
}
```

### 2. Failed Transaction Debugging

```javascript
// Debug failed transactions
async function debugFailedTransaction(txHash) {
  const receipt = await provider.getTransactionReceipt(txHash);
  
  if (!receipt) {
    return { error: 'Receipt not found' };
  }
  
  if (receipt.status === 1) {
    return { status: 'success' };
  }
  
  // Get transaction details for more context
  const tx = await provider.getTransaction(txHash);
  
  // Try to decode revert reason
  try {
    const result = await provider.call({
      to: tx.to,
      from: tx.from,
      data: tx.data,
      value: tx.value,
      gasLimit: tx.gasLimit
    }, tx.blockNumber - 1);
  } catch (error) {
    return {
      status: 'failed',
      gasUsed: receipt.gasUsed.toString(),
      gasLimit: tx.gasLimit.toString(),
      revertReason: error.reason || error.message,
      block: receipt.blockNumber
    };
  }
}
```

### 3. Multi-Transaction Batch Analysis

```javascript
// Analyze batch of transactions
async function analyzeBatch(txHashes) {
  const processor = new ReceiptProcessor(provider);
  const results = [];
  
  for (const hash of txHashes) {
    const receipt = await processor.getReceipt(hash);
    const cost = await processor.calculateTotalCost(hash);
    
    results.push({
      hash: hash,
      status: receipt?.status,
      gasUsed: receipt?.gasUsed,
      totalCost: cost?.totalCost,
      l1Cost: cost?.l1Cost,
      blockNumber: receipt?.blockNumber
    });
  }
  
  // Calculate statistics
  const successful = results.filter(r => r.status === 'success').length;
  const totalGas = results.reduce((sum, r) => sum + BigInt(r.gasUsed || 0), 0n);
  
  return {
    transactions: results,
    statistics: {
      total: txHashes.length,
      successful: successful,
      failed: txHashes.length - successful,
      totalGasUsed: totalGas.toString()
    }
  };
}
```

---

## eth_hashrate - Get node hashrate

# eth_hashrate - Get node hashrate

Get node hashrate on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_hashrate",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_maxPriorityFeePerGas - Get priority fee...

# eth_maxPriorityFeePerGas - Get priority fee...

Returns the priority fee needed for inclusion in the next block on the Neuroweb network. This method is essential for EIP-1559 transactions, helping you determine the appropriate tip to incentivize miners.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_maxPriorityFeePerGas",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `QUANTITY` - The hex-encoded priority fee per gas in wei needed for inclusion in the next block.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x77359400"
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_mining - Check if node is mining

# eth_mining - Check if node is mining

Check if node is mining on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_mining",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_newBlockFilter - Subscribe to new blocks

# eth_newBlockFilter - Subscribe to new blocks

Subscribe to new blocks on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newBlockFilter",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newBlockFilter',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_newFilter - Create event filter

# eth_newFilter - Create event filter

Creates a filter object, based on filter options, to notify when the state changes (logs) on the Neuroweb network. This method is essential for tracking smart contract events and state changes.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newFilter",
        "params": [{
          "fromBlock": "0x1",
          "toBlock": "0x2",
          "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
          "topics": [
            "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"
          ]
        }],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `filterID` (string): A hexadecimal filter identifier to be used with: `eth_getFilterChanges` - Get new logs since last poll `eth_getFilterLogs` - Get all accumulated logs `eth_uninstallFilter` - Remove the filter when no longer needed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x990a0ab959f87cc519ae825a7e6e7a46"
}
```

## Implementation Example

cURL
JavaScript
Python

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1",
      "toBlock": "0x2",
      "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
      "topics": [
        "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"
      ]
    }],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newFilter',
    params: [{
      fromBlock: '0x1',
      toBlock: '0x2',
      address: '0x8888f1f195afa192cfee860698584c030f4c9db1',
      topics: [
        '0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b'
      ]
    }],
    id: 1
  })
});

const data = await response.json();
const filterID = data.result;
console.log('Filter ID:', filterID);
```

```python
import requests
import json

url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
headers = {'Content-Type': 'application/json'}
payload = {
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
        "fromBlock": "0x1",
        "toBlock": "0x2",
        "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
        "topics": [
            "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"
        ]
    }],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
data = response.json()
filter_id = data['result']
print(f'Filter ID: {filter_id}')
```

## Advanced Usage

### Monitor Multiple Contracts

```json
{
  "params": [{
    "fromBlock": "latest",
    "address": [
      "0x1234567890abcdef1234567890abcdef12345678",
      "0xabcdef1234567890abcdef1234567890abcdef12"
    ]
  }]
}
```

### Complex Topic Filtering

```json
{
  "params": [{
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",  // Transfer event
      null,  // Any sender
      [      // Specific recipients
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ]
    ]
  }]
}
```

### Monitor All Events from Latest Block

```json
{
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest"
  }]
}
```

## Workflow Example

```javascript
// 1. Create filter
const createFilter = await fetch(url, {
  method: 'POST',
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newFilter',
    params: [{ fromBlock: 'latest' }],
    id: 1
  })
});
const { result: filterID } = await createFilter.json();

// 2. Poll for changes
const getChanges = await fetch(url, {
  method: 'POST',
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getFilterChanges',
    params: [filterID],
    id: 2
  })
});
const { result: logs } = await getChanges.json();

// 3. Clean up
const uninstall = await fetch(url, {
  method: 'POST',
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_uninstallFilter',
    params: [filterID],
    id: 3
  })
});
```

## Notes

- **Block Range Limits**: Free plans typically limited to 5 blocks, paid plans up to 10,000 blocks
- **Filter Timeout**: Filters expire after \~5 minutes of inactivity - poll regularly with `eth_getFilterChanges`
- **Topics Order**: Topics are order-dependent; the first topic is usually the event signature hash
- **Filter Management**: Always uninstall filters when done to free up resources
- **Performance**: Create specific filters to reduce the amount of data processed

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Neuroweb documentation](https://www.dwellir.com/docs/neuroweb).*

---

## eth_newPendingTransactionFilter - Monitor p...

# eth_newPendingTransactionFilter - Monitor p...

Monitor pending transactions on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_newPendingTransactionFilter",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_newPendingTransactionFilter',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_protocolVersion - Get protocol version

# eth_protocolVersion - Get protocol version

Get protocol version on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_protocolVersion",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_sendRawTransaction - Broadcast Signed T...

# eth_sendRawTransaction - Broadcast Signed T...

Submits a pre-signed transaction to the network for broadcast and execution. Returns the transaction hash if successful.

## When to Use This Method

`eth_sendRawTransaction` is required for:

- **Sending ETH** - Transfer value between accounts
- **Token Transfers** - Execute ERC20/NFT transfers
- **Contract Interactions** - Call state-changing functions
- **Contract Deployment** - Deploy new smart contracts

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Common Use Cases

### 1. Safe Transaction Broadcasting

```javascript
// Broadcast with safety checks
async function safeBroadcast(wallet, transaction) {
  // Pre-flight checks
  const balance = await wallet.provider.getBalance(wallet.address);
  const estimatedCost = transaction.gasLimit * transaction.maxFeePerGas;
  
  if (balance < estimatedCost + transaction.value) {
    throw new Error('Insufficient balance for transaction');
  }
  
  // Check nonce
  const expectedNonce = await wallet.provider.getTransactionCount(wallet.address);
  if (transaction.nonce && transaction.nonce !== expectedNonce) {
    console.warn(`Nonce mismatch: expected ${expectedNonce}, got ${transaction.nonce}`);
  }
  
  // Sign transaction
  const signedTx = await wallet.signTransaction(transaction);
  
  // Broadcast with retry
  let attempts = 0;
  while (attempts < 3) {
    try {
      const txHash = await wallet.provider.send('eth_sendRawTransaction', [signedTx]);
      return txHash;
    } catch (error) {
      if (error.message.includes('already known')) {
        // Transaction already sent
        return ethers.Transaction.from(signedTx).hash;
      }
      attempts++;
      if (attempts === 3) throw error;
      await new Promise(r => setTimeout(r, 1000 * attempts));
    }
  }
}
```

### 2. Optimized Gas Strategy

```javascript
// Dynamic gas price management
async function optimizedSend(wallet, to, value) {
  const provider = wallet.provider;
  
  // Get network conditions
  const [block, feeData, gasPrice] = await Promise.all([
    provider.getBlock('latest'),
    provider.getFeeData(),
    provider.getGasPrice()
  ]);
  
  // Calculate optimal fees
  const baseFee = block.baseFeePerGas;
  const priorityFee = feeData.maxPriorityFeePerGas;
  
  // Adjust based on network congestion
  const congestionFactor = Number(baseFee) / Number(parseUnits('10', 'gwei'));
  const adjustedPriorityFee = priorityFee * BigInt(Math.ceil(congestionFactor));
  
  const transaction = {
    to: to,
    value: parseEther(value),
    type: 2,
    chainId: 1,
    maxFeePerGas: baseFee * 2n + adjustedPriorityFee,
    maxPriorityFeePerGas: adjustedPriorityFee,
    gasLimit: 21000n
  };
  
  const signedTx = await wallet.signTransaction(transaction);
  return await provider.send('eth_sendRawTransaction', [signedTx]);
}
```

### 3. Transaction Queue Management

```javascript
// Manage transaction queue
class TransactionQueue {
  constructor(wallet) {
    this.wallet = wallet;
    this.queue = [];
    this.processing = false;
  }
  
  async add(transaction) {
    this.queue.push(transaction);
    if (!this.processing) {
      this.process();
    }
  }
  
  async process() {
    this.processing = true;
    
    while (this.queue.length > 0) {
      const tx = this.queue.shift();
      
      try {
        // Add nonce
        tx.nonce = await this.wallet.provider.getTransactionCount(this.wallet.address);
        
        // Sign and send
        const signedTx = await this.wallet.signTransaction(tx);
        const hash = await this.wallet.provider.send('eth_sendRawTransaction', [signedTx]);
        
        console.log(`Transaction sent: ${hash}`);
        
        // Wait for confirmation before next
        await this.wallet.provider.waitForTransaction(hash);
      } catch (error) {
        console.error('Transaction failed:', error);
        // Optionally re-queue or handle error
      }
    }
    
    this.processing = false;
  }
}
```

---

## eth_sendTransaction - Send transaction (wal...

# eth_sendTransaction - Send transaction (wal...

> **Important**: Dwellir's shared Neuroweb endpoints do not manage user private keys. JSON-RPC nodes cannot unlock your account, so `eth_sendTransaction` calls will fail. Sign transactions client-side and broadcast them with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/neuroweb/eth_sendRawTransaction).

## Why this method is disabled on shared nodes

- [`eth_sendTransaction` requires the node to hold and unlock the `from` account's private key](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction).
- Managed infrastructure providers disable it for security reasons rather than storing customer keys on shared servers (for example, [Infura explicitly blocks the method on shared endpoints](https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_sendtransaction)).

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (defaults to estimate if omitted)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei for legacy transactions
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Priority fee in wei (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Amount of native token to transfer
- `data` (`DATA, optional`): Contract call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): Transaction hash returned when the request is accepted by a node that can sign and broadcast transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "unknown account"
  }
}
```

## Recommended workflow

1. Build the raw transaction locally with your wallet or SDK.
2. Sign the payload client-side (hardware wallet, custodial service, or library).
3. Submit the signed hex string with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/neuroweb/eth_sendRawTransaction).

## Example response from the shared endpoint

```bash
curl -s -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0x0000000000000000000000000000000000000000"}],"id":1}'
```

```json
{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"unknown account"}}
```

Need help? Contact our [support team](mailto:support@dwellir.com) or use the dedicated [`eth_sendRawTransaction`](https://www.dwellir.com/docs/neuroweb/eth_sendRawTransaction) guide.

---

## eth_signTransaction - Sign transaction (rar...

# eth_signTransaction - Sign transaction (rar...

Signs a transaction using an unlocked account on the node. **Important**: Most RPC providers don't support this method for security reasons, as it requires private keys to be stored on the server.

## Security Considerations

- This method requires an unlocked account on the node
- Private keys must be available to the RPC server
- Most production RPC providers disable this method
- Use client-side signing libraries instead for better security

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_signTransaction",
        "params": [{
          "from": "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
          "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
          "gas": "0x76c0",
          "gasPrice": "0x9184e72a000",
          "value": "0x9184e72a"
        }],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `DATA` - The signed transaction data, ready for transmission via `eth_sendRawTransaction`.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xf86c808504a817c8008276c094d46e8dd67c5d32be8058bb8eb970870f072445675849184e72a8001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
      "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_signTransaction',
    params: [{
      from: '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83',
      to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_syncing - Check node sync status

# eth_syncing - Check node sync status

Check node sync status on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_syncing",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_syncing',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_uninstallFilter - Uninstall Filter

# eth_uninstallFilter - Uninstall Filter

Remove filter subscription on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_uninstallFilter",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_uninstallFilter',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## grandpa_roundState - Neuroweb RPC Method

# grandpa_roundState - Neuroweb RPC Method

Returns the state of the current GRANDPA finality round on Neuroweb when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`grandpa_roundState` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Neuroweb, critical for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/neuroweb/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/neuroweb/system_health) -- Check overall node health including sync and peer status

---

## net_listening - Check if node is listening

# net_listening - Check if node is listening

Check if node is listening on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "net_listening",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## net_peerCount - Get connected peer count

# net_peerCount - Get connected peer count

Get connected peer count on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "net_peerCount",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## net_version - Get network ID

# net_version - Get network ID

Get network ID on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "net_version",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## payment_queryFeeDetails - Neuroweb RPC Method

# payment_queryFeeDetails - Neuroweb RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Neuroweb. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`payment_queryFeeDetails` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Neuroweb
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/neuroweb/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/neuroweb/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/neuroweb/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/neuroweb/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Neuroweb RPC Method

# payment_queryInfo - Neuroweb RPC Method

Estimates the fee for an encoded extrinsic on Neuroweb. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`payment_queryInfo` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Neuroweb
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/neuroweb/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/neuroweb/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/neuroweb/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/neuroweb/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Neuroweb RPC Method

# rpc_methods - Neuroweb RPC Method

Returns a list of all RPC methods exposed by the Neuroweb node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`rpc_methods` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Neuroweb node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Neuroweb endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Neuroweb endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/neuroweb/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/neuroweb/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Neuroweb RPC Method

# state_call - Neuroweb RPC Method

Calls a runtime API function on Neuroweb and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`state_call` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/neuroweb/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/neuroweb/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/neuroweb/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/neuroweb/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/neuroweb/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - Neuroweb RPC Method

# state_getKeysPaged - Neuroweb RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Neuroweb. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`state_getKeysPaged` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Neuroweb
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-neuroweb.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/neuroweb/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/neuroweb/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Neuroweb RPC Method

# state_getMetadata - Neuroweb RPC Method

Returns the runtime metadata for Neuroweb as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`state_getMetadata` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Neuroweb
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Neuroweb:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Neuroweb:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/neuroweb/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/neuroweb/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Neuroweb RPC Method

# state_getRuntimeVersion - Neuroweb RPC Method

Returns the runtime version information for Neuroweb, including the spec name, spec version, implementation version, and supported API versions.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`state_getRuntimeVersion` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Neuroweb
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Neuroweb in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/neuroweb/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Neuroweb RPC Method

# state_getStorage - Neuroweb RPC Method

Returns the SCALE-encoded storage value for a given key on Neuroweb. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`state_getStorage` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Neuroweb
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/neuroweb/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/neuroweb/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Neuroweb RPC Method

# state_queryStorageAt - Neuroweb RPC Method

Queries multiple storage keys at a specific block on Neuroweb, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`state_queryStorageAt` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Neuroweb
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/neuroweb/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/neuroweb/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/neuroweb/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/neuroweb/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Neuroweb RPC Method

# system_chain - Neuroweb RPC Method

Returns the chain name of the Neuroweb network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`system_chain` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Network Verification** -- Confirm your application is connected to the correct Neuroweb network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Neuroweb"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', 'Neuroweb');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/neuroweb/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/neuroweb/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/neuroweb/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/neuroweb/rpc_methods) -- List all available RPC methods

---

## system_health - Neuroweb RPC Method

# system_health - Neuroweb RPC Method

Returns the health status of the Neuroweb node, including peer count, sync state, and whether the node expects to have peers.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`system_health` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Neuroweb
- **Load Balancing** - Route requests only to healthy, fully synced nodes for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Neuroweb:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Neuroweb nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/neuroweb/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Neuroweb RPC Method

# system_name - Neuroweb RPC Method

Returns the node implementation name on Neuroweb. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`system_name` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Neuroweb
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Neuroweb node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Neuroweb node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Neuroweb node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Neuroweb node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Neuroweb node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Neuroweb nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/neuroweb/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/neuroweb/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/neuroweb/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/neuroweb/rpc_methods) -- List all available RPC methods

---

## system_properties - Neuroweb RPC Method

# system_properties - Neuroweb RPC Method

Returns the chain-specific properties for Neuroweb, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`system_properties` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Neuroweb
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/neuroweb/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/neuroweb/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/neuroweb/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/neuroweb/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/neuroweb/rpc_methods) -- List all available RPC methods

---

## system_version - Neuroweb RPC Method

# system_version - Neuroweb RPC Method

Returns the node implementation version string on Neuroweb. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Neuroweb?** Build on the decentralized AI blockchain powering 125M+ Knowledge Assets with MIT-awarded technology with OriginTrail DKG V8 with 500-1000x scalability, 40% of US imports secured, EVM compatibility, and Best Decentralized AI Project (MIT).

## When to Use This Method

`system_version` is essential for AI developers, knowledge graph builders, and teams requiring verifiable AI solutions:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Neuroweb
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for decentralized knowledge graphs (DKG), verifiable AI, supply chain audits, and knowledge mining
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Neuroweb node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Neuroweb node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-neuroweb.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Neuroweb node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-neuroweb.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Neuroweb node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-neuroweb.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Neuroweb node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Neuroweb nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/neuroweb/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/neuroweb/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/neuroweb/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/neuroweb/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/neuroweb/rpc_methods) -- List all available RPC methods

---

## web3_clientVersion - Get client version

# web3_clientVersion - Get client version

Get client version on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "web3_clientVersion",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## web3_sha3 - Calculate Keccak-256 Hash on Ne...

# web3_sha3 - Calculate Keccak-256 Hash on Ne...

Calculate Keccak-256 hash on the Neuroweb network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "web3_sha3",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-neuroweb.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-neuroweb.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_sha3',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## opBNB RPC with Dwellir

# opBNB RPC with Dwellir

## opBNB RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where opBNB supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on opBNB?

opBNB is BNB Chain's Layer 2 solution, designed to offer ultra-low fees and lightning-fast transaction processing. Built on Optimism's OP Stack, opBNB delivers:

### **Ultra-High Performance**

- **Sub-second block times** - Experience instant transaction confirmations
- **100x lower fees** than BNB Smart Chain mainnet
- **150M gas limit** - Massive throughput for complex applications

### **Enterprise-Grade Security**

- **Backed by BNB Chain** - Leverages proven Layer 1 infrastructure
- **Optimistic rollup technology** - Inherits Ethereum-level security guarantees
- **Battle-tested architecture** - Built on proven OP Stack foundation

### **Thriving Ecosystem**

- **Native BNB token** - No new tokens to manage
- **EVM compatibility** - Deploy existing contracts seamlessly
- **Growing DeFi ecosystem** - Access to expanding financial infrastructure

## Quick Start with opBNB

Connect to opBNB in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to opBNB mainnet
const provider = new JsonRpcProvider(
  'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to opBNB mainnet
const web3 = new Web3(
  'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to opBNB:', chainId === 204);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { opBNB } from 'viem/chains';

// Create opBNB client
const client = createPublicClient({
  chain: opBNB,
  transport: http('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to opBNB mainnet
w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Verify connection
print(f"Connected: {w3.is_connected()}")
print(f"Chain ID: {w3.eth.chain_id}")
print(f"Latest block: {w3.eth.block_number}")

# Get account balance
balance = w3.eth.get_balance('0x...')
print(f"Balance: {w3.from_wei(balance, 'ether')} BNB")
```

## Network Information

| Parameter    | Value    | Details      |
| ------------ | -------- | ------------ |
| Chain ID     | 204      | Mainnet      |
| Gas Limit    | 150M     | Per block    |
| Gas Token    | BNB      | Native token |
| RPC Standard | Ethereum | JSON-RPC 2.0 |

## API Reference

opBNB supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods plus Layer 2 optimizations.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Check transaction status
  if (receipt.status === 1) {
    console.log('Transaction confirmed:', receipt.transactionHash);
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on opBNB Layer 2:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

// Estimate gas for transaction
const gasEstimate = await provider.estimateGas({
  to: recipient,
  value: amount,
  data: '0x'
});

// Calculate total cost
const totalCost = gasEstimate * feeData.gasPrice;
console.log(`Transaction cost: ${totalCost} wei`);
```

### Event Filtering

Efficiently query contract events with pagination:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 5000; // opBNB recommended batch size

  const currentBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class OpBNBProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Wrong Chain ID Error

opBNB uses specific chain IDs for mainnet and testnet:

```javascript
// Always verify chain ID matches expected network
const chainId = await provider.send('eth_chainId', []);

if (chainId === '0xcc') {
  console.log('Connected to opBNB Mainnet (204)');
} else if (chainId === '0x15eb') {
  console.log('Connected to opBNB Testnet (5611)');
} else {
  throw new Error(`Unexpected chain ID: ${chainId}`);
}
```

### Transaction Underpriced Error

opBNB uses dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Rate Limit Exceeded

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## FAQs

**Q: What's the difference between opBNB and BNB Smart Chain?**
A: opBNB is a Layer 2 scaling solution built on top of BNB Smart Chain, offering much lower fees and faster transactions while maintaining full EVM compatibility.

**Q: Can I use the same wallet for opBNB and BSC?**
A: Yes, any Ethereum-compatible wallet works with opBNB. Simply add the opBNB network configuration to your wallet.

**Q: How do I bridge assets to opBNB?**
A: Use the official [opBNB Bridge](https://opbnb-bridge.bnbchain.org) to transfer assets between BNB Smart Chain and opBNB.

## Smoke Tests

### Quick Connection Tests

**Mainnet Connection:**

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

**Testnet Connection:**

```bash
curl -X POST https://api-opbnb-testnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Ethers.js Verification:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Test connection
const blockNumber = await provider.getBlockNumber();
const network = await provider.getNetwork();

console.log(`Block: ${blockNumber}, Chain ID: ${network.chainId}`);
```

### Web3.py Verification:

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

print(f"Connected: {w3.is_connected()}")
print(f"Chain ID: {w3.eth.chain_id}")
print(f"Block Number: {w3.eth.block_number}")
```

## Migration Guide

### From BNB Smart Chain to opBNB

Migrating from BSC to opBNB requires minimal code changes:

```javascript
// Before (BSC)
const provider = new JsonRpcProvider('https://bsc-dataseed.bnbchain.org');

// After (opBNB)
const provider = new JsonRpcProvider(
  'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (204 vs 56)
// Note: Separate block numbers
// Note: Much lower gas fees
```

## Resources & Tools

### Official Resources

- [opBNB Documentation](https://docs.bnbchain.org/bnb-opbnb/)
- [opBNB Bridge](https://opbnb-bridge.bnbchain.org)
- [opBNB Block Explorer](https://opbnbscan.com)

### Developer Tools

- [opBNB Documentation](https://docs.bnbchain.org/bnb-opbnb/)
- [Remix IDE Integration](https://remix.ethereum.org)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on opBNB with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - opBNB RPC Method

# debug_traceBlock - opBNB RPC Method

Traces all transactions in a block on opBNB by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for opBNB - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on opBNB
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on opBNB:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in opBNB blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/opbnb/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/opbnb/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - opBNB RPC Method

# debug_traceBlockByHash - opBNB RPC Method

Traces all transactions in a block on opBNB identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for opBNB - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on opBNB
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on opBNB:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on opBNB:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/opbnb/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/opbnb/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/opbnb/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/opbnb/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - opBNB RPC Method

# debug_traceBlockByNumber - opBNB RPC Method

Traces all transactions in a block on opBNB identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for opBNB - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of opBNB execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on opBNB:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on opBNB:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/opbnb/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/opbnb/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/opbnb/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - opBNB RPC Method

# debug_traceCall - opBNB RPC Method

Traces a call on opBNB without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for opBNB - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on opBNB
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on opBNB to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on opBNB:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on opBNB:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/opbnb/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/opbnb/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - opBNB RPC Method

# debug_traceTransaction - opBNB RPC Method

Traces a transaction execution on opBNB by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on opBNB
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/opbnb/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/opbnb/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - opBNB RPC Method

# eth_accounts - opBNB RPC Method

Returns a list of addresses owned by the client on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/opbnb/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/opbnb/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - opBNB RPC Method

# eth_blockNumber - opBNB RPC Method

Returns the number of the most recent block on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_blockNumber` is fundamental for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Syncing Applications** - Keep your dApp in sync with the latest opBNB blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('opBNB block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('opBNB block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'opBNB block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'opBNB block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("opBNB block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on opBNB:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on opBNB:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your opBNB node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/opbnb/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/opbnb/eth_syncing) - Check if node is still syncing

---

## eth_call - opBNB RPC Method

# eth_call - opBNB RPC Method

Executes a new message call immediately without creating a transaction on opBNB. Used for reading smart contract state.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

The `eth_call` method serves these key scenarios for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on opBNB
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on opBNB. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on opBNB
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on opBNB

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - opBNB RPC Method

# eth_chainId - opBNB RPC Method

Returns the chain ID used for transaction signing on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_chainId` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/opbnb/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/opbnb/eth_syncing) - Check sync status

---

## eth_coinbase - opBNB RPC Method

# eth_coinbase - opBNB RPC Method

Checks the legacy `eth_coinbase` compatibility method on opBNB. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('opBNB coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('opBNB coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'opBNB coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'opBNB coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("opBNB coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of opBNB nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/opbnb/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/opbnb/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/opbnb/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - opBNB RPC Method

# eth_estimateGas - opBNB RPC Method

Estimates the gas necessary to execute a transaction on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on opBNB
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on opBNB.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like opBNB may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/opbnb/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - opBNB RPC Method

# eth_feeHistory - opBNB RPC Method

Returns historical gas fee data on opBNB, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on opBNB without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on opBNB.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on opBNB) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/opbnb/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/opbnb/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - opBNB RPC Method

# eth_gasPrice - opBNB RPC Method

Returns the current gas price on opBNB in wei.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on opBNB
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of opBNB. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on opBNB, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on opBNB: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if opBNB supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/opbnb/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/opbnb/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - opBNB RPC Method

# eth_getBalance - opBNB RPC Method

Returns the balance of a given address on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getBalance` is fundamental for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Wallet applications**: Display user balances and enable balance-dependent operations on opBNB
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to opBNB
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on opBNB. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} opBNB`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on opBNB at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 opBNB')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 opBNB')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on opBNB.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/opbnb/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/opbnb/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - opBNB RPC Method

# eth_getBlockByHash - opBNB RPC Method

Returns information about a block by hash on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getBlockByHash` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on opBNB
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on opBNB.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on opBNB.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/opbnb/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - opBNB RPC Method

# eth_getBlockByNumber - opBNB RPC Method

Returns information about a block by block number on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getBlockByNumber` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on opBNB
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on opBNB with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on opBNB. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/opbnb/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/opbnb/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/opbnb/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - opBNB RPC Method

# eth_getBlockReceipts - opBNB RPC Method

Returns all transaction receipts for a block on opBNB. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getBlockReceipts` is useful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for opBNB, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on opBNB. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x95db196d5589ba674d0397bf718f513e7d0e8509ba6829bd3e4435b87562e286",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/opbnb/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/opbnb/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - opBNB RPC Method

# eth_getCode - opBNB RPC Method

Returns the bytecode at a given address on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getCode` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on opBNB
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on opBNB:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on opBNB:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/opbnb/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/opbnb/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - opBNB RPC Method

# eth_getFilterChanges - opBNB RPC Method

Polls a filter on opBNB for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getFilterChanges` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on opBNB
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on opBNB:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/opbnb/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/opbnb/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/opbnb/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/opbnb/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/opbnb/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - opBNB RPC Method

# eth_getFilterLogs - opBNB RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on opBNB. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getFilterLogs` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on opBNB
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/opbnb/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/opbnb/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/opbnb/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/opbnb/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - opBNB RPC Method

# eth_getLogs - opBNB RPC Method

Returns an array of all logs matching a given filter object on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on opBNB for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on opBNB
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on opBNB.

```javascript
const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if opBNB enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on opBNB, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/opbnb/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/opbnb/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - opBNB RPC Method

# eth_getStorageAt - opBNB RPC Method

Returns the value from a storage position at a given address on opBNB. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getStorageAt` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **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 fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-opbnb-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 = '0x4200000000000000000000000000000000000006'
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-opbnb-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-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 opBNB:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-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-opbnb-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 = '0x4200000000000000000000000000000000000006';
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 opBNB:`);
  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/opbnb/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/opbnb/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/opbnb/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - opBNB RPC Method

# eth_getTransactionByHash - opBNB RPC Method

Returns the information about a transaction by transaction hash on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getTransactionByHash` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on opBNB
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on opBNB. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on opBNB. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/opbnb/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - opBNB RPC Method

# eth_getTransactionCount - opBNB RPC Method

Returns the number of transactions sent from an address on opBNB, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getTransactionCount` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on opBNB
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('opBNB nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'opBNB nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("opBNB nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on opBNB:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/opbnb/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/opbnb/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/opbnb/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - opBNB RPC Method

# eth_getTransactionReceipt - opBNB RPC Method

Returns the receipt of a transaction by transaction hash on opBNB. Receipt is only available for mined transactions.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_getTransactionReceipt` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on opBNB and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on opBNB. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on opBNB, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xf8ee79d0a4a8ab785a1971caa68937195b4908c72d749a38c3188ed967501f1d")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/opbnb/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/opbnb/eth_getLogs) - Query logs by filter

---

## eth_hashrate - opBNB RPC Method

# eth_hashrate - opBNB RPC Method

Returns the legacy `eth_hashrate` compatibility value on opBNB. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('opBNB hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('opBNB hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'opBNB hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'opBNB hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("opBNB hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/opbnb/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/opbnb/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/opbnb/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - opBNB RPC Method

# eth_maxPriorityFeePerGas - opBNB RPC Method

Returns the current suggested priority fee (tip) per gas in wei on opBNB. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on opBNB
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('opBNB priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'opBNB priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("opBNB priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on opBNB:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on opBNB:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/opbnb/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/opbnb/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/opbnb/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - opBNB RPC Method

# eth_mining - opBNB RPC Method

Checks the legacy `eth_mining` compatibility method on opBNB. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('opBNB mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('opBNB mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'opBNB mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'opBNB mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("opBNB mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/opbnb/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/opbnb/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/opbnb/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - opBNB RPC Method

# eth_newBlockFilter - opBNB RPC Method

Creates a filter on opBNB that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_newBlockFilter` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Block Monitoring** - Detect new blocks on opBNB as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on opBNB:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/opbnb/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/opbnb/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/opbnb/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/opbnb/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - opBNB RPC Method

# eth_newFilter - opBNB RPC Method

Creates a filter object on opBNB based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_newFilter` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Event Monitoring** - Subscribe to specific contract events on opBNB such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on opBNB:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/opbnb/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/opbnb/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/opbnb/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/opbnb/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/opbnb/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - opBNB RPC Method

# eth_newPendingTransactionFilter - opBNB RPC Method

Creates a filter on opBNB that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Mempool Monitoring** - Observe unconfirmed transactions on opBNB to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for fully on-chain games, high-frequency DeFi, and cost-sensitive applications on BNB Chain

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on opBNB...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on opBNB:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/opbnb/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/opbnb/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/opbnb/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - opBNB RPC Method

# eth_protocolVersion - opBNB RPC Method

Returns the current Ethereum protocol version used by the opBNB node.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_protocolVersion` is useful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('opBNB protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('opBNB protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'opBNB protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'opBNB protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("opBNB protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of opBNB nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/opbnb/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/opbnb/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/opbnb/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - opBNB RPC Method

# eth_sendRawTransaction - opBNB RPC Method

Submits a pre-signed transaction for broadcast to opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to opBNB
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the opBNB mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/opbnb/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/opbnb/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/opbnb/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - opBNB RPC Method

# eth_sendTransaction - opBNB RPC Method

Creates and sends a new transaction from an unlocked account on opBNB. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('opBNB tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('opBNB tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'opBNB tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'opBNB tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("opBNB tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on opBNB dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/opbnb/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/opbnb/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - opBNB RPC Method

# eth_signTransaction - opBNB RPC Method

Signs a transaction with the private key of the specified account on opBNB without submitting it to the network.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed opBNB tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed opBNB tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed opBNB tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on opBNB:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/opbnb/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/opbnb/eth_accounts) - List accounts available for signing

---

## eth_syncing - opBNB RPC Method

# eth_syncing - opBNB RPC Method

Returns the sync status of your opBNB node - either `false` when fully synced, or an object describing the sync progress.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_syncing` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('opBNB node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('opBNB node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("opBNB node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/opbnb/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/opbnb/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/opbnb/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/opbnb/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - opBNB RPC Method

# eth_uninstallFilter - opBNB RPC Method

Removes a filter on opBNB that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`eth_uninstallFilter` is important for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/opbnb/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/opbnb/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/opbnb/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/opbnb/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/opbnb/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - opBNB RPC Method

# net_listening - opBNB RPC Method

Checks whether the connected opBNB client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`net_listening` is useful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('opBNB node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'opBNB node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("opBNB node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/opbnb/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/opbnb/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/opbnb/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/opbnb/web3_clientVersion) - Get node client info

---

## net_peerCount - opBNB RPC Method

# net_peerCount - opBNB RPC Method

Returns the number of peers currently connected to your opBNB node.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`net_peerCount` is important for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific opBNB deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`opBNB peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'opBNB peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("opBNB peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of opBNB nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/opbnb/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/opbnb/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/opbnb/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/opbnb/web3_clientVersion) - Get node client info

---

## net_version - opBNB RPC Method

# net_version - opBNB RPC Method

Returns the current network ID on opBNB as a decimal string. The network ID identifies which network the node is connected to.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`net_version` is essential for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Endpoint Identification** - Confirm your application is connected to the expected opBNB network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('opBNB network ID:', networkId);

// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'opBNB network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("opBNB network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/opbnb/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/opbnb/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/opbnb/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/opbnb/eth_syncing) - Check node sync progress

---

## rpc_modules - opBNB RPC Method

# rpc_modules - opBNB RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected opBNB endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`rpc_modules` is useful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/opbnb/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/opbnb/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - opBNB RPC Method

# web3_clientVersion - opBNB RPC Method

Returns the current client software version string for your opBNB node, including the client name, version number, OS, and runtime.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

## When to Use This Method

`web3_clientVersion` is valuable for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('opBNB client:', clientVersion);

// Using fetch
const response = await fetch('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'opBNB client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("opBNB client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/opbnb/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/opbnb/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/opbnb/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/opbnb/net_peerCount) - Get number of connected peers

---

## web3_sha3 - opBNB RPC Method

# web3_sha3 - opBNB RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on opBNB.

> **Why opBNB?** Build on Binance's high-performance L2 processing 100M+ daily transactions with the lowest L2 gas fees with sub-$0.0001 gas fees, 5-10K TPS, sub-second block times via Volta/Maxwell upgrades, and OP Stack architecture.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for GameFi developers, high-frequency dApp builders, and teams requiring BNB Chain integration:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-opbnb-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/opbnb/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/opbnb/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/opbnb/web3_clientVersion) - Get node client version

---

## Optimism RPC - Fast & Reliable Optimism Node API

# Optimism RPC - Fast & Reliable Optimism Node API

## Optimism RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Optimism supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Network Overview

Optimism is a Layer 2 scaling solution for Ethereum that uses optimistic rollups to achieve faster transactions and lower fees while maintaining Ethereum's security. As one of the leading L2 solutions, Optimism provides an EVM-equivalent environment that makes it easy for developers to deploy existing Ethereum applications.

## Key Features

### High Performance

- **Fast Transactions**: Sub-second block times with instant transaction confirmation
- **Low Costs**: Up to 100x lower gas fees compared to Ethereum mainnet
- **High Throughput**: Process thousands of transactions per second

### Security & Reliability

- **Ethereum Security**: Inherits security from Ethereum mainnet
- **Fraud Proofs**: Optimistic rollup design with challenge period for security
- **99.99% Uptime**: Enterprise-grade infrastructure with global redundancy

### Developer Experience

- **EVM Equivalence**: Deploy existing Solidity contracts without modification
- **Full JSON-RPC**: Complete [Ethereum JSON-RPC API](https://ethereum.org/developers/docs/apis/json-rpc/) compatibility
- **Archive Data**: Access to full historical blockchain data
- **Debug & Trace APIs**: Advanced debugging capabilities for developers

Optimism-specific helpers such as `rollup_getInfo`, `rollup_gasPrices`, and `eth_estimateL1Fee` are not exposed on Dwellir's public Optimism endpoints. Use standard Ethereum JSON-RPC methods for fee estimation and consult Optimism's own docs for rollup metadata.

## Quick Start

## Network Information

### Mainnet Configuration

| Parameter       | Value                                                | Details |
| --------------- | ---------------------------------------------------- | ------- |
| Network Name    | Optimism Mainnet                                     |         |
| Chain ID        | 10 (0xa)                                             |         |
| Currency Symbol | ETH                                                  |         |
| Block Explorer  | [Optimism Explorer](https://optimistic.etherscan.io) |         |

### Testnet Configuration

| Parameter       | Value                                                              | Details |
| --------------- | ------------------------------------------------------------------ | ------- |
| Network Name    | Optimism Sepolia                                                   |         |
| Chain ID        | 11155420 (0xaa37dc)                                                |         |
| Currency Symbol | ETH                                                                |         |
| Block Explorer  | [Optimism Sepolia Explorer](https://sepolia-optimism.etherscan.io) |         |

## Supported APIs

Our Optimism endpoints support the complete Ethereum JSON-RPC specification plus Optimism-specific methods:

### Core APIs

- **Standard Ethereum JSON-RPC**: All eth\_\* methods
- **Web3 Methods**: web3\_clientVersion, web3\_sha3
- **Net Methods**: net\_version, net\_listening, net\_peerCount
- **Debug API**: Transaction and block tracing
- **Filter API**: Event and log filtering
- **Subscription API**: Real-time updates via WebSocket

### Optimism Compatibility

- **Gas Estimation**: Use `eth_estimateGas` and `eth_gasPrice` for standard fee checks
- **Rollup Helpers**: `rollup_getInfo`, `rollup_gasPrices`, and `eth_estimateL1Fee` return `Method not found` on the public archive endpoints
- **Sequencer Status**: Check Optimism's own status and documentation for rollup-level health details

## Use Cases

### DeFi Applications

Build decentralized exchanges, lending protocols, and yield optimizers with low transaction costs and fast confirmation times.

### NFT Marketplaces

Deploy NFT collections and marketplaces with affordable minting and trading, perfect for high-volume applications.

### Gaming & Metaverse

Create blockchain games and virtual worlds where users can perform frequent transactions without high gas costs.

### DAO Infrastructure

Implement governance systems with affordable voting and proposal execution, enabling more democratic participation.

## Integration Examples

### Web3.js

```javascript
const Web3 = require('web3');
const web3 = new Web3('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await web3.eth.getBlock('latest');
console.log('Latest block:', block.number);

// Check balance
const balance = await web3.eth.getBalance('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0');
console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'ETH');
```

### Ethers.js

```javascript
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get network info
const network = await provider.getNetwork();
console.log('Connected to:', network.name, 'Chain ID:', network.chainId);

// Estimate L2 gas
const gasPrice = await provider.getFeeData();
console.log('Gas price:', ethers.formatUnits(gasPrice.gasPrice, 'gwei'), 'gwei');
```

### viem

```typescript
import { createPublicClient, http } from 'viem';
import { optimism } from 'viem/chains';

const client = createPublicClient({
  chain: optimism,
  transport: http('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'),
});

// Get chain ID
const chainId = await client.getChainId();
console.log('Chain ID:', chainId);

// Read contract
const balance = await client.getBalance({
  address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0',
});
console.log('Balance:', balance);
```

## Migration Guide

### From Other Providers

Migrating to Dwellir is simple:

1. Sign up for an API key at [dashboard.dwellir.com](https://dashboard.dwellir.com)
2. Replace your current RPC URL with Dwellir's Optimism endpoint
3. No code changes required - we support the full Ethereum JSON-RPC spec

### From Ethereum Mainnet

Deploying from Ethereum to Optimism:

1. Your Solidity contracts work without modification
2. Use the same deployment tools (Hardhat, Truffle, Foundry)
3. Update your provider URL to our Optimism endpoint
4. Benefit from 100x lower gas costs

## Best Practices

### Optimize for L2

- **Batch Operations**: Group multiple operations to save on L1 data costs
- **Event Monitoring**: Use filters and subscriptions for efficient event tracking
- **Gas Estimation**: Always estimate both L1 and L2 costs before transactions

### Error Handling

```javascript
try {
  const result = await provider.send('eth_call', [tx, 'latest']);
  return result;
} catch (error) {
  if (error.code === -32603) {
    // Internal error, retry with exponential backoff
    await delay(1000);
    return retry();
  }
  throw error;
}
```

## Troubleshooting

### Common Issues

**Connection Timeouts**

- Check your API key is valid
- Ensure you're using the correct network endpoint
- Verify your firewall allows HTTPS connections

**Nonce Too Low**

- Optimism processes transactions quickly
- Always fetch the latest nonce before sending transactions
- Consider using pending nonce for successive transactions

**L1 Data Fee Estimation**

- Use `eth_estimateGas` for L2 execution cost
- Calculate L1 data fee separately using rollup gas oracle
- Total cost = L2 execution cost + L1 data cost

## Additional Resources

- [Optimism Official Documentation](https://docs.optimism.io)
- [Optimism GitHub](https://github.com/ethereum-optimism)
- [Block Explorer](https://optimistic.etherscan.io)
- [Network Status](https://status.optimism.io)
- [Bridge Interface](https://app.optimism.io/bridge)

## Support

Need help with your Optimism integration?

- Email: <support@dwellir.com>
- Documentation: [Full API Reference](https://www.dwellir.com/docs/optimism)
- Dashboard: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

Start building on Optimism with Dwellir's reliable RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register) and join thousands of developers scaling Ethereum applications.

---

## debug_traceBlock - Optimism RPC Method

# debug_traceBlock - Optimism RPC Method

Traces all transactions in a block on Optimism by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Optimism - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Optimism
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Optimism:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Optimism blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/optimism/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/optimism/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/optimism/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/optimism/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Optimism RPC Method

# debug_traceBlockByHash - Optimism RPC Method

Traces all transactions in a block on Optimism identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Optimism - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Optimism
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Optimism:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Optimism:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/optimism/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/optimism/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/optimism/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/optimism/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/optimism/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Optimism RPC Method

# debug_traceBlockByNumber - Optimism RPC Method

Traces all transactions in a block on Optimism identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Optimism - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Optimism execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Optimism:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Optimism:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/optimism/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/optimism/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/optimism/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/optimism/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Optimism RPC Method

# debug_traceCall - Optimism RPC Method

Traces a call on Optimism without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Optimism - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Optimism
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Optimism to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Optimism:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Optimism:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/optimism/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/optimism/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/optimism/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/optimism/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Optimism RPC Method

# debug_traceTransaction - Optimism RPC Method

Traces a transaction execution on Optimism by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Optimism
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/optimism/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/optimism/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Optimism RPC Method

# eth_accounts - Optimism RPC Method

Returns a list of addresses owned by the client on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for L2 builders, DeFi developers, and teams launching Superchain-compatible apps in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/optimism/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/optimism/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Optimism RPC Method

# eth_blockNumber - Optimism RPC Method

Returns the number of the most recent block on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_blockNumber` is fundamental for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Syncing Applications** - Keep your dApp in sync with the latest Optimism blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Optimism block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Optimism block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Optimism block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Optimism block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Optimism block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Optimism:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Optimism:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Optimism node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/optimism/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/optimism/eth_syncing) - Check if node is still syncing

---

## eth_call - Optimism RPC Method

# eth_call - Optimism RPC Method

Executes a new message call immediately without creating a transaction on Optimism. Used for reading smart contract state.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

The `eth_call` method serves these key scenarios for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Optimism
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const walletAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Optimism. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Optimism
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Optimism

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    data := common.FromHex("0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Optimism RPC Method

# eth_chainId - Optimism RPC Method

Returns the chain ID used for transaction signing on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_chainId` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/optimism/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/optimism/eth_syncing) - Check sync status

---

## eth_coinbase - Optimism RPC Method

# eth_coinbase - Optimism RPC Method

Checks the legacy `eth_coinbase` compatibility method on Optimism. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for L2 builders, DeFi developers, and teams launching Superchain-compatible apps when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Optimism coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Optimism coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Optimism coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Optimism coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Optimism coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Optimism nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/optimism/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/optimism/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/optimism/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Optimism RPC Method

# eth_estimateGas - Optimism RPC Method

Estimates the gas necessary to execute a transaction on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Optimism
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Optimism.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Optimism may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/optimism/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 Data Fee

# eth_estimateL1Fee - Estimate L1 Data Fee

Dwellir's public Optimism endpoints do not expose the L1 fee oracle on the shared archive surface. A live call to `eth_estimateL1Fee` returns `-32601`.

## When to Use This Method

Use this page to confirm that a public Dwellir Optimism endpoint does not currently expose the L1 fee oracle. For standard transaction pricing, use `eth_estimateGas` and `eth_gasPrice`.

## Request Parameters

- `txObject` (`Object, required`): Optimism transaction object to estimate.

## Request Example

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [{
          "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
          "to": "0x4200000000000000000000000000000000000006",
          "value": "0xde0b6b3a7640000",
          "data": "0xa9059cbb0000000000000000000000008ba1f109551bd432803012645hac136c0000000000000000000000000000000000000000000000000de0b6b3a7640000"
        }],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Fee estimation payload returned by nodes that implement eth_estimateL1Fee

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_estimateL1Fee does not exist/is not available"
  }
}
```

## Live Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_estimateL1Fee does not exist/is not available"
  }
}
```

## Fallback Check

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function supportsL1FeeOracle(txObject) {
  try {
    await provider.send('eth_estimateL1Fee', [txObject]);
    return true;
  } catch (error) {
    if (error?.code === -32601) {
      return false;
    }
    throw error;
  }
}

console.log('L1 fee oracle available:', await supportsL1FeeOracle({
  to: '0x0000000000000000000000000000000000000000',
  data: '0x'
}));
```

## Supported Alternatives

- Use `eth_estimateGas` for execution cost.
- Use `eth_gasPrice` for current gas pricing.
- Use the Optimism documentation if you need a separate L1 data fee oracle.

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Optimism documentation](https://www.dwellir.com/docs/optimism).*

---

## eth_feeHistory - Optimism RPC Method

# eth_feeHistory - Optimism RPC Method

Returns historical gas fee data on Optimism, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Optimism without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Optimism.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Optimism) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/optimism/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/optimism/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Optimism RPC Method

# eth_gasPrice - Optimism RPC Method

Returns the current gas price on Optimism in wei.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Optimism
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Optimism. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Optimism, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Optimism: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Optimism supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/optimism/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/optimism/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Optimism RPC Method

# eth_getBalance - Optimism RPC Method

Returns the balance of a given address on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getBalance` is fundamental for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Optimism
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Optimism
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Optimism. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Optimism`);
  return balance;
}

displayBalance('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Optimism at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Optimism')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Optimism')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Optimism.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/optimism/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/optimism/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Optimism RPC Method

# eth_getBlockByHash - Optimism RPC Method

Returns information about a block by hash on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getBlockByHash` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Optimism
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Optimism.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Optimism.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/optimism/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Optimism RPC Method

# eth_getBlockByNumber - Optimism RPC Method

Returns information about a block by block number on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getBlockByNumber` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Optimism
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Optimism with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Optimism. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/optimism/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/optimism/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/optimism/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Optimism RPC Method

# eth_getBlockReceipts - Optimism RPC Method

Returns all transaction receipts for a block on Optimism. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getBlockReceipts` is useful for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Optimism, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Optimism. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x76cde4f6f885fe27962356115e0ff0539058a03e8b9e15dac3fb40a9caa0bc47",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/optimism/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/optimism/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Optimism RPC Method

# eth_getCode - Optimism RPC Method

Returns the bytecode at a given address on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getCode` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Optimism
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Optimism:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Optimism:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/optimism/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/optimism/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Optimism RPC Method

# eth_getFilterChanges - Optimism RPC Method

Polls a filter on Optimism for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getFilterChanges` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Optimism
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Optimism:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/optimism/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/optimism/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/optimism/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/optimism/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/optimism/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Optimism RPC Method

# eth_getFilterLogs - Optimism RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Optimism. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getFilterLogs` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Optimism
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/optimism/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/optimism/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/optimism/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/optimism/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Optimism RPC Method

# eth_getLogs - Optimism RPC Method

Returns an array of all logs matching a given filter object on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Optimism for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Optimism
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Optimism.

```javascript
const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Optimism enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Optimism, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/optimism/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/optimism/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Optimism RPC Method

# eth_getStorageAt - Optimism RPC Method

Returns the value from a storage position at a given address on Optimism. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getStorageAt` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **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 cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **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": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "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-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '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-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

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-optimism-mainnet-archive.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 = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
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-optimism-mainnet-archive.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-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    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 Optimism:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.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-optimism-mainnet-archive.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 = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
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 Optimism:`);
  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/optimism/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/optimism/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/optimism/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Optimism RPC Method

# eth_getTransactionByHash - Optimism RPC Method

Returns the information about a transaction by transaction hash on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getTransactionByHash` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Optimism
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Optimism. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Optimism. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/optimism/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Optimism RPC Method

# eth_getTransactionCount - Optimism RPC Method

Returns the number of transactions sent from an address on Optimism, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getTransactionCount` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Optimism
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Optimism nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
nonce = get_transaction_count(address)
print(f'Optimism nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Optimism nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Optimism:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/optimism/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/optimism/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/optimism/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Optimism RPC Method

# eth_getTransactionReceipt - Optimism RPC Method

Returns the receipt of a transaction by transaction hash on Optimism. Receipt is only available for mined transactions.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_getTransactionReceipt` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Optimism and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Optimism. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Optimism, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/optimism/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/optimism/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Optimism RPC Method

# eth_hashrate - Optimism RPC Method

Returns the legacy `eth_hashrate` compatibility value on Optimism. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Optimism hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Optimism hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Optimism hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Optimism hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Optimism hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/optimism/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/optimism/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/optimism/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Optimism RPC Method

# eth_maxPriorityFeePerGas - Optimism RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Optimism. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Optimism
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Optimism priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Optimism priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Optimism priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Optimism:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Optimism:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/optimism/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/optimism/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/optimism/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Optimism RPC Method

# eth_mining - Optimism RPC Method

Checks the legacy `eth_mining` compatibility method on Optimism. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Optimism mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Optimism mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Optimism mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Optimism mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Optimism mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/optimism/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/optimism/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/optimism/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Optimism RPC Method

# eth_newBlockFilter - Optimism RPC Method

Creates a filter on Optimism that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_newBlockFilter` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Block Monitoring** - Detect new blocks on Optimism as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Optimism:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/optimism/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/optimism/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/optimism/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/optimism/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Optimism RPC Method

# eth_newFilter - Optimism RPC Method

Creates a filter object on Optimism based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_newFilter` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Event Monitoring** - Subscribe to specific contract events on Optimism such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Optimism:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/optimism/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/optimism/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/optimism/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/optimism/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/optimism/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Optimism RPC Method

# eth_newPendingTransactionFilter - Optimism RPC Method

Creates a filter on Optimism that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Mempool Monitoring** - Observe unconfirmed transactions on Optimism to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Optimism...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Optimism:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/optimism/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/optimism/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/optimism/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Optimism RPC Method

# eth_protocolVersion - Optimism RPC Method

Returns the current Ethereum protocol version used by the Optimism node.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_protocolVersion` is useful for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Optimism protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Optimism protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Optimism protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Optimism protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Optimism protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Optimism nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/optimism/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/optimism/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/optimism/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Optimism RPC Method

# eth_sendRawTransaction - Optimism RPC Method

Submits a pre-signed transaction for broadcast to Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Optimism
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Optimism mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/optimism/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/optimism/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/optimism/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Optimism RPC Method

# eth_sendTransaction - Optimism RPC Method

Creates and sends a new transaction from an unlocked account on Optimism. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for L2 builders, DeFi developers, and teams launching Superchain-compatible apps in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Optimism tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Optimism tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Optimism tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Optimism tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Optimism tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Optimism dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/optimism/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/optimism/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Optimism RPC Method

# eth_signTransaction - Optimism RPC Method

Signs a transaction with the private key of the specified account on Optimism without submitting it to the network.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for L2 builders, DeFi developers, and teams launching Superchain-compatible apps in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Optimism tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Optimism tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Optimism tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Optimism:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/optimism/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/optimism/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/optimism/eth_accounts) - List accounts available for signing

---

## eth_syncing - Optimism RPC Method

# eth_syncing - Optimism RPC Method

Returns the sync status of your Optimism node - either `false` when fully synced, or an object describing the sync progress.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_syncing` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Optimism node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Optimism node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Optimism node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/optimism/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/optimism/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/optimism/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/optimism/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Optimism RPC Method

# eth_uninstallFilter - Optimism RPC Method

Removes a filter on Optimism that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`eth_uninstallFilter` is important for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/optimism/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/optimism/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/optimism/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/optimism/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/optimism/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Optimism RPC Method

# net_listening - Optimism RPC Method

Checks whether the connected Optimism client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`net_listening` is useful for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Optimism node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Optimism node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Optimism node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/optimism/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/optimism/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/optimism/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/optimism/web3_clientVersion) - Get node client info

---

## net_peerCount - Optimism RPC Method

# net_peerCount - Optimism RPC Method

Returns the number of peers currently connected to your Optimism node.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`net_peerCount` is important for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Optimism deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Optimism peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Optimism peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Optimism peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Optimism nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/optimism/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/optimism/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/optimism/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/optimism/web3_clientVersion) - Get node client info

---

## net_version - Optimism RPC Method

# net_version - Optimism RPC Method

Returns the current network ID on Optimism as a decimal string. The network ID identifies which network the node is connected to.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`net_version` is essential for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Endpoint Identification** - Confirm your application is connected to the expected Optimism network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Optimism network ID:', networkId);

// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Optimism network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Optimism network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/optimism/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/optimism/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/optimism/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/optimism/eth_syncing) - Check node sync progress

---

## rollup_gasPrices - Get Rollup Gas Prices

# rollup_gasPrices - Get Rollup Gas Prices

Dwellir's public Optimism endpoints do not expose `rollup_gasPrices`. A live call returns `-32601 Method not found`.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup gas price data returned by nodes that implement rollup_gasPrices

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Live Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Fallback Check

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function supportsRollupGasPrices() {
  try {
    await provider.send('rollup_gasPrices', []);
    return true;
  } catch (error) {
    if (error?.code === -32601) {
      return false;
    }
    throw error;
  }
}

console.log('Rollup gas prices available:', await supportsRollupGasPrices());
```

## Supported Alternatives

- Use `eth_gasPrice` for current gas pricing.
- Use `eth_estimateGas` for execution cost.
- Use Optimism's own documentation if you need rollup-level pricing fields.

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Optimism documentation](https://www.dwellir.com/docs/optimism).*

---

## rollup_getInfo - Get Rollup Information

# rollup_getInfo - Get Rollup Information

Dwellir's public Optimism endpoints do not expose Optimism rollup metadata on the shared archive surface. A live call to `rollup_getInfo` returns `-32601`.

## When to Use This Method

Use this page when you need to confirm that a public Dwellir Optimism endpoint does not expose rollup metadata. For fee and chain checks, use standard Ethereum JSON-RPC methods instead.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_getInfo",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup metadata object returned by nodes that implement rollup_getInfo

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Live Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Fallback Check

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function supportsRollupInfo() {
  try {
    await provider.send('rollup_getInfo', []);
    return true;
  } catch (error) {
    if (error?.code === -32601) {
      return false;
    }
    throw error;
  }
}

console.log('Rollup metadata available:', await supportsRollupInfo());
```

## Supported Alternatives

- Use `eth_chainId` to confirm you are connected to Optimism mainnet or Sepolia.
- Use `eth_gasPrice` and `eth_estimateGas` for standard transaction pricing.
- Use the Optimism documentation if you need `mode`, `synced_l1`, `safe_l2`, or `unsafe_l2`.

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [Optimism documentation](https://www.dwellir.com/docs/optimism).*

---

## trace_block - Optimism RPC Method

# trace_block - Optimism RPC Method

Returns traces for all transactions in a block on Optimism.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Optimism
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Optimism chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/optimism/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/optimism/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/optimism/trace_get) - Get a specific trace by index

---

## trace_call - Optimism RPC Method

# trace_call - Optimism RPC Method

Traces a call without creating a transaction on Optimism, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Optimism
- **Pre-execution analysis** - Test contract interactions without spending gas for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
    data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
        'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/optimism/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/optimism/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/optimism/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Optimism RPC Method

# trace_callMany - Optimism RPC Method

Traces multiple calls in sequence on Optimism, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Optimism
- **Historical state comparison** - Compare how the same call would execute at different points in Optimism chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}, ["trace"]],
      [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}, ["trace"]],
        [{"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045' }, ['trace']],
    [{ to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'data': '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045'}, ['trace']],
        [{'to': '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/optimism/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/optimism/eth_call) - Execute call without trace

---

## trace_filter - Optimism RPC Method

# trace_filter - Optimism RPC Method

Returns traces matching a filter on Optimism.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Optimism
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/optimism/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/optimism/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/optimism/eth_getLogs) - Filter event logs

---

## trace_get - Optimism RPC Method

# trace_get - Optimism RPC Method

Returns a trace at a specific position within a transaction on Optimism.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Optimism
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/optimism/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/optimism/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Optimism RPC Method

# trace_replayBlockTransactions - Optimism RPC Method

Replays all transactions in a block on Optimism and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Optimism
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Optimism chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/optimism/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/optimism/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/optimism/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Optimism RPC Method

# trace_replayTransaction - Optimism RPC Method

Replays a transaction on Optimism and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Optimism
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/optimism/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/optimism/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/optimism/trace_block) - Get all traces in a block

---

## trace_transaction - Optimism RPC Method

# trace_transaction - Optimism RPC Method

Returns all traces for a specific transaction on Optimism.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for cross-chain DeFi, Superchain-interoperable dApps, and public goods funding recipients
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Optimism
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x43ac31f47abf56b34e0903e390dd9a1820ee7f03a6359cf2ef08d7152eb26cf3'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/optimism/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/optimism/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/optimism/trace_filter) - Filter traces by criteria

---

## web3_clientVersion - Optimism RPC Method

# web3_clientVersion - Optimism RPC Method

Returns the current client software version string for your Optimism node, including the client name, version number, OS, and runtime.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

## When to Use This Method

`web3_clientVersion` is valuable for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Optimism client:', clientVersion);

// Using fetch
const response = await fetch('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Optimism client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Optimism client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/optimism/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/optimism/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/optimism/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/optimism/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Optimism RPC Method

# web3_sha3 - Optimism RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Optimism.

> **Why Optimism?** Build on the heart of the Superchain powering 60%+ of Ethereum L2 transactions with $6B+ TVL with OP Stack modularity, Superchain interoperability, 17M+ daily transactions across 33 chains, and 20% of tokens for public goods.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for L2 builders, DeFi developers, and teams launching Superchain-compatible apps:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-optimism-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/optimism/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/optimism/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/optimism/web3_clientVersion) - Get node client version

---

## Plasma RPC with Dwellir

# Plasma RPC with Dwellir

## Plasma RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Plasma supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why build on Plasma?

Plasma is an EVM Layer 1 for stablecoin payments. It runs PlasmaBFT consensus and a Reth execution client. Block time is 1 second. You pay gas in XPL.

Existing Solidity contracts deploy without changes. Hardhat, Foundry, ethers.js, viem, and MetaMask work as they do on Ethereum. Payment apps and wallets use Plasma for 1 second confirmation and standard Ethereum JSON-RPC.

### **Stablecoin payments**

- **1 second blocks** - confirmation times that fit checkout and payout flows
- **XPL gas** - EIP-1559 fees paid in the native token
- **EVM contracts** - keep the Solidity you already ship

### **Standard Ethereum tooling**

- **JSON-RPC** - the same methods you use on Ethereum
- **Debug and txpool** - Dwellir exposes `debug_*` and `txpool_*` on this endpoint
- **HTTPS and WebSocket** - including `eth_subscribe` for newHeads

### **Network facts**

- **Chain ID 9745** - Plasma Mainnet Beta
- **Explorer** - [plasmascan.to](https://plasmascan.to/)
- **Full nodes** - Dwellir does not advertise archive state

## Quick start with Plasma

Connect to Plasma Mainnet Beta with Dwellir:

### Installation and setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const chainId = await provider.send('eth_chainId', []);
console.log('Plasma chain ID:', parseInt(chainId, 16));

const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);
```

```javascript
const { Web3 } = require('web3');

const web3 = new Web3(
  'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const chainId = await web3.eth.getChainId();
console.log('Connected to Plasma:', chainId === 9745n);

const gasPrice = await web3.eth.getGasPrice();
console.log('Gas price:', web3.utils.fromWei(gasPrice, 'gwei'), 'gwei');
```

```typescript
import { createPublicClient, defineChain, http } from 'viem';

const plasma = defineChain({
  id: 9745,
  name: 'Plasma',
  nativeCurrency: {
    name: 'Plasma',
    symbol: 'XPL',
    decimals: 18,
  },
  rpcUrls: {
    default: {
      http: ['https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
  blockExplorers: {
    default: {
      name: 'PlasmaScan',
      url: 'https://plasmascan.to',
    },
  },
});

const client = createPublicClient({
  chain: plasma,
  transport: http('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

const blockNumber = await client.getBlockNumber();
console.log('Latest block:', blockNumber);
```

```python
from web3 import Web3

web3 = Web3(Web3.HTTPProvider(
  'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'
))

print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # 9745
print('Latest block:', web3.eth.block_number)
```

## Network information

| Parameter    | Value    | Details             |
| ------------ | -------- | ------------------- |
| Chain ID     | 9745     | Plasma Mainnet Beta |
| Block time   | 1 second | PlasmaBFT           |
| Native token | XPL      | 18 decimals         |
| RPC standard | Ethereum | JSON-RPC 2.0        |
| Node type    | Full     | Not archive         |

## API reference

Plasma supports standard Ethereum JSON-RPC methods. Dwellir's endpoint also exposes debug and txpool. Trace methods are not available on this endpoint.

## Add Plasma to MetaMask

Add a custom network.

- Network name: Plasma Mainnet Beta
- RPC URL: `https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY`
- Chain ID: 9745
- Currency: XPL
- Explorer: <https://plasmascan.to/>

## Related guides

- [Stablecoin L1 RPC guide: Arc, Tempo, Plasma and Stable](https://www.dwellir.com/blog/stablechain-rpc-guide)
- [Top Plasma RPC providers compared](https://www.dwellir.com/blog/top-plasma-rpc-providers)

---

## debug_traceBlock - Plasma RPC Method

# debug_traceBlock - Plasma RPC Method

Traces all transactions in a block on Plasma by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Plasma - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Plasma
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Plasma:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Plasma blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/plasma/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/plasma/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/plasma/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/plasma/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Plasma RPC Method

# debug_traceBlockByHash - Plasma RPC Method

Traces all transactions in a block on Plasma identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Plasma - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Plasma
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Plasma:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Plasma:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/plasma/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/plasma/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/plasma/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/plasma/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/plasma/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Plasma RPC Method

# debug_traceBlockByNumber - Plasma RPC Method

Traces all transactions in a block on Plasma identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Plasma - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Plasma execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Plasma:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Plasma:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/plasma/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/plasma/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/plasma/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/plasma/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Plasma RPC Method

# debug_traceCall - Plasma RPC Method

Traces a call on Plasma without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Plasma - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Plasma
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "data": "0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
        "data": "0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
        "data": "0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    data: '0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    data: '0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    'data': '0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
        "data": "0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Plasma to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Plasma:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Plasma:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/plasma/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/plasma/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/plasma/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/plasma/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Plasma RPC Method

# debug_traceTransaction - Plasma RPC Method

Traces a transaction execution on Plasma by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Plasma
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/plasma/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/plasma/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Plasma RPC Method

# eth_accounts - Plasma RPC Method

Returns a list of addresses owned by the client on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/plasma/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/plasma/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Plasma RPC Method

# eth_blockNumber - Plasma RPC Method

Returns the number of the most recent block on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_blockNumber` is fundamental for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Syncing Applications** - Keep your dApp in sync with the latest Plasma blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Plasma block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Plasma block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Plasma block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Plasma block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Plasma block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Plasma:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Plasma:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Plasma node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/plasma/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/plasma/eth_syncing) - Check if node is still syncing

---

## eth_call - Plasma RPC Method

# eth_call - Plasma RPC Method

Executes a new message call immediately without creating a transaction on Plasma. Used for reading smart contract state.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

The `eth_call` method serves these key scenarios for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Plasma
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on stablecoin transfers, payment apps, and wallets that need 1 second confirmation

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';
const walletAddress = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Plasma. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Plasma
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Plasma

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "data": "0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "data": "0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    data := common.FromHex("0x70a08231000000000000000000000000B8CE59FC3717ada4C02eaDF9682A9e934F625ebb")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Plasma RPC Method

# eth_chainId - Plasma RPC Method

Returns the chain ID used for transaction signing on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_chainId` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on stablecoin transfers, payment apps, and wallets that need 1 second confirmation

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/plasma/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/plasma/eth_syncing) - Check sync status

---

## eth_estimateGas - Plasma RPC Method

# eth_estimateGas - Plasma RPC Method

Estimates the gas necessary to execute a transaction on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Plasma
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Plasma.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Plasma may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/plasma/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Plasma RPC Method

# eth_feeHistory - Plasma RPC Method

Returns historical gas fee data on Plasma, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Plasma without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Plasma.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Plasma) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/plasma/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/plasma/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Plasma RPC Method

# eth_gasPrice - Plasma RPC Method

Returns the current gas price on Plasma in wei.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Plasma
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Plasma. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Plasma, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Plasma: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Plasma supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/plasma/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/plasma/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Plasma RPC Method

# eth_getBalance - Plasma RPC Method

Returns the balance of a given address on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getBalance` is fundamental for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Plasma
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Plasma
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Plasma. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Plasma`);
  return balance;
}

displayBalance('0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Plasma at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Plasma')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Plasma')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Plasma.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/plasma/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/plasma/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Plasma RPC Method

# eth_getBlockByHash - Plasma RPC Method

Returns information about a block by hash on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getBlockByHash` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Plasma
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Plasma.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Plasma.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/plasma/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Plasma RPC Method

# eth_getBlockByNumber - Plasma RPC Method

Returns information about a block by block number on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getBlockByNumber` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Plasma
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Plasma with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Plasma. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/plasma/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/plasma/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/plasma/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Plasma RPC Method

# eth_getBlockReceipts - Plasma RPC Method

Returns all transaction receipts for a block on Plasma. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getBlockReceipts` is useful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Plasma, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Plasma. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/plasma/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/plasma/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Plasma RPC Method

# eth_getCode - Plasma RPC Method

Returns the bytecode at a given address on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getCode` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Plasma
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on stablecoin transfers, payment apps, and wallets that need 1 second confirmation

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Plasma:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Plasma:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/plasma/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/plasma/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Plasma RPC Method

# eth_getFilterChanges - Plasma RPC Method

Polls a filter on Plasma for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getFilterChanges` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Plasma
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Plasma:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/plasma/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/plasma/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/plasma/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/plasma/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/plasma/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Plasma RPC Method

# eth_getFilterLogs - Plasma RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Plasma. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getFilterLogs` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Plasma
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/plasma/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/plasma/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/plasma/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/plasma/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Plasma RPC Method

# eth_getLogs - Plasma RPC Method

Returns an array of all logs matching a given filter object on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Plasma for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Plasma
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Plasma.

```javascript
const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Plasma enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Plasma, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/plasma/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/plasma/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Plasma RPC Method

# eth_getStorageAt - Plasma RPC Method

Returns the value from a storage position at a given address on Plasma. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getStorageAt` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **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 stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **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": [
    "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "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-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', '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-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';

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-plasma-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 = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
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-plasma-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-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    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 Plasma:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-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-plasma-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 = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';
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 Plasma:`);
  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/plasma/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/plasma/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/plasma/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Plasma RPC Method

# eth_getTransactionByHash - Plasma RPC Method

Returns the information about a transaction by transaction hash on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getTransactionByHash` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Plasma
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Plasma. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Plasma. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/plasma/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Plasma RPC Method

# eth_getTransactionCount - Plasma RPC Method

Returns the number of transactions sent from an address on Plasma, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getTransactionCount` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Plasma
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Plasma nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'
nonce = get_transaction_count(address)
print(f'Plasma nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Plasma nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Plasma:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/plasma/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/plasma/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/plasma/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Plasma RPC Method

# eth_getTransactionReceipt - Plasma RPC Method

Returns the receipt of a transaction by transaction hash on Plasma. Receipt is only available for mined transactions.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_getTransactionReceipt` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Plasma and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Plasma. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Plasma, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xb7db21f5fcc47ea4f33c75deebf128eb8aaecaece720d3503e8752ec29df3e0f")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/plasma/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/plasma/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Plasma RPC Method

# eth_hashrate - Plasma RPC Method

Returns the legacy `eth_hashrate` compatibility value on Plasma. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Plasma hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Plasma hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Plasma hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Plasma hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Plasma hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- `eth_mining` - Check if the node is actively mining
- `eth_coinbase` - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/plasma/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Plasma RPC Method

# eth_maxPriorityFeePerGas - Plasma RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Plasma. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Plasma
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Plasma priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Plasma priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Plasma priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Plasma:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Plasma:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/plasma/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/plasma/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/plasma/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_newBlockFilter - Plasma RPC Method

# eth_newBlockFilter - Plasma RPC Method

Creates a filter on Plasma that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_newBlockFilter` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Block Monitoring** - Detect new blocks on Plasma as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Plasma:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/plasma/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/plasma/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/plasma/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/plasma/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Plasma RPC Method

# eth_newFilter - Plasma RPC Method

Creates a filter object on Plasma based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_newFilter` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Event Monitoring** - Subscribe to specific contract events on Plasma such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Plasma:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/plasma/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/plasma/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/plasma/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/plasma/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/plasma/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Plasma RPC Method

# eth_newPendingTransactionFilter - Plasma RPC Method

Creates a filter on Plasma that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Mempool Monitoring** - Observe unconfirmed transactions on Plasma to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for stablecoin transfers, payment apps, and wallets that need 1 second confirmation

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Plasma...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Plasma:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/plasma/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/plasma/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/plasma/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Plasma RPC Method

# eth_protocolVersion - Plasma RPC Method

Returns the current Ethereum protocol version used by the Plasma node.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_protocolVersion` is useful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Plasma protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Plasma protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Plasma protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Plasma protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Plasma protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Plasma nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/plasma/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/plasma/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/plasma/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Plasma RPC Method

# eth_sendRawTransaction - Plasma RPC Method

Submits a pre-signed transaction for broadcast to Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Plasma
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Plasma mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/plasma/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/plasma/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/plasma/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Plasma RPC Method

# eth_sendTransaction - Plasma RPC Method

Creates and sends a new transaction from an unlocked account on Plasma. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Plasma tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Plasma tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Plasma tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Plasma tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Plasma tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Plasma dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/plasma/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/plasma/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Plasma RPC Method

# eth_signTransaction - Plasma RPC Method

Signs a transaction with the private key of the specified account on Plasma without submitting it to the network.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Plasma tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Plasma tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Plasma tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Plasma:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/plasma/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/plasma/eth_accounts) - List accounts available for signing

---

## eth_syncing - Plasma RPC Method

# eth_syncing - Plasma RPC Method

Returns the sync status of your Plasma node - either `false` when fully synced, or an object describing the sync progress.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_syncing` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Plasma node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Plasma node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Plasma node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/plasma/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/plasma/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/plasma/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/plasma/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Plasma RPC Method

# eth_uninstallFilter - Plasma RPC Method

Removes a filter on Plasma that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`eth_uninstallFilter` is important for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/plasma/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/plasma/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/plasma/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/plasma/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/plasma/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Plasma RPC Method

# net_listening - Plasma RPC Method

Checks whether the connected Plasma client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`net_listening` is useful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Plasma node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Plasma node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Plasma node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/plasma/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/plasma/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/plasma/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/plasma/web3_clientVersion) - Get node client info

---

## net_peerCount - Plasma RPC Method

# net_peerCount - Plasma RPC Method

Returns the number of peers currently connected to your Plasma node.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`net_peerCount` is important for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Plasma deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Plasma peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Plasma peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Plasma peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Plasma nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/plasma/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/plasma/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/plasma/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/plasma/web3_clientVersion) - Get node client info

---

## net_version - Plasma RPC Method

# net_version - Plasma RPC Method

Returns the current network ID on Plasma as a decimal string. The network ID identifies which network the node is connected to.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`net_version` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Endpoint Identification** - Confirm your application is connected to the expected Plasma network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Plasma network ID:', networkId);

// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Plasma network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Plasma network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/plasma/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/plasma/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/plasma/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/plasma/eth_syncing) - Check node sync progress

---

## txpool_content - Plasma RPC Method

# txpool_content - Plasma RPC Method

Returns the full pending and queued transaction pool for the connected Plasma endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`txpool_content` is useful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/plasma/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/plasma/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/plasma/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Plasma RPC Method

# txpool_status - Plasma RPC Method

Returns transaction pool counters for the connected Plasma endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`txpool_status` is valuable for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/plasma/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/plasma/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/plasma/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Plasma RPC Method

# web3_clientVersion - Plasma RPC Method

Returns the current client software version string for your Plasma node, including the client name, version number, OS, and runtime.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

## When to Use This Method

`web3_clientVersion` is valuable for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Plasma client:', clientVersion);

// Using fetch
const response = await fetch('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Plasma client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Plasma client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/plasma/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/plasma/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/plasma/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/plasma/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Plasma RPC Method

# web3_sha3 - Plasma RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Plasma.

> **Why Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/plasma/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/plasma/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/plasma/web3_clientVersion) - Get node client version

---

## Polkadot RPC Documentation

# Polkadot RPC Documentation

## Polkadot RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Polkadot supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Overview

Polkadot is a next-generation blockchain protocol that connects multiple specialized blockchains into one unified network. Built on the Substrate framework, Polkadot enables cross-chain transfers of any type of data or asset, not just tokens.

This documentation provides comprehensive coverage of Polkadot's JSON-RPC API methods, enabling developers to interact with Polkadot nodes for building applications, wallets, explorers, and other blockchain tools.

## Network Information

### Mainnet (Polkadot)

| Parameter    | Value                           | Details |
| ------------ | ------------------------------- | ------- |
| Chain ID     | Polkadot                        |         |
| Native Token | DOT                             |         |
| Consensus    | Nominated Proof-of-Stake (NPoS) |         |

## Connection Endpoints

## Authentication

Authentication is done via the URL path. Replace `{YOUR_API_KEY}` with your actual API key obtained from [dwellir.com](https://www.dwellir.com).

## API Reference

Browse the core Substrate method groups supported by Polkadot, including `system_*`, `chain_*`, `state_*`, `author_*`, `payment_*`, and `rpc_methods`. Polkadot also exposes `grandpa_*` and `beefy_*` where applicable.

## Quick Start Examples

### Get Latest Block

```javascript
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_getBlock',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Latest block:', data.result);
```

### Submit Transaction

```python
import requests
import json

url = "https://api-polkadot.n.dwellir.com/YOUR_API_KEY"
headers = {
    "Content-Type": "application/json"
}

# Properly formatted and signed extrinsic
extrinsic = "0x..."

payload = {
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": [extrinsic],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
tx_hash = response.json()["result"]
print(f"Transaction hash: {tx_hash}")
```

### Subscribe to New Blocks (WebSocket)

```javascript
const WebSocket = require('ws');

const ws = new WebSocket('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_subscribeNewHeads',
    params: [],
    id: 1
  }));
});

ws.on('message', (data) => {
  const response = JSON.parse(data);
  if (response.params?.result) {
    console.log('New block:', response.params.result);
  }
});
```

## Error Handling

Polkadot RPC errors follow the JSON-RPC 2.0 error format:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "Expected hex-encoded hash"
  },
  "id": 1
}
```

### Common Error Codes

| Code   | Message          | Description               |
| ------ | ---------------- | ------------------------- |
| -32700 | Parse error      | Invalid JSON              |
| -32600 | Invalid request  | Missing required fields   |
| -32601 | Method not found | Unknown RPC method        |
| -32602 | Invalid params   | Invalid method parameters |
| -32603 | Internal error   | Node processing error     |
| -32000 | Server error     | Custom server errors      |

## Best Practices

### 1. Connection Management

- Use WebSocket connections for subscriptions and real-time updates
- Implement reconnection logic for WebSocket disconnections
- Use HTTPS for single queries and transactions

### 2. Error Handling

- Always check for error responses before processing results
- Implement retry logic with exponential backoff
- Log errors for debugging and monitoring

### 3. Performance Optimization

- Batch multiple queries when possible
- Cache frequently accessed data like metadata
- Use specific block hashes for deterministic queries

### 4. Security

- Never expose API keys in client-side code
- Validate all input data before submission
- Use secure storage for private keys

## SDK Support

### Official Libraries

- **@polkadot/api** - JavaScript/TypeScript SDK
- **py-substrate-interface** - Python SDK
- **subxt** - Rust SDK
- **go-substrate-rpc-client** - Go SDK

### Integration Example

```javascript
// Using @polkadot/api
const { ApiPromise, WsProvider } = require('@polkadot/api');

async function connect() {
  const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');

  const api = await ApiPromise.create({ provider });

  // Query chain data
  const chain = await api.rpc.system.chain();
  console.log(`Connected to ${chain}`);

  return api;
}
```

## Additional Resources

- [Polkadot Wiki](https://wiki.polkadot.network/)
- [Substrate Documentation](https://docs.substrate.io/)
- [Polkadot JS Apps](https://polkadot.js.org/apps/)
- [Network Explorer](https://polkadot.subscan.io/)

## Support

For additional support or questions:

- Email: <support@dwellir.com>
- Documentation: [dwellir.com/docs](https://www.dwellir.com/docs)

***

## Method Categories

Select a category below to explore detailed method documentation:

---

## author_pendingExtrinsics - Polkadot RPC Method

# author_pendingExtrinsics - Polkadot RPC Method

Returns all pending extrinsics currently in the transaction pool on Polkadot. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`author_pendingExtrinsics` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on Polkadot
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the Polkadot transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/polkadot/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/polkadot/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/polkadot/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - Polkadot RPC Method

# author_rotateKeys - Polkadot RPC Method

Generate a new set of session keys on Polkadot. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`author_rotateKeys` is critical for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Validator Setup** - Generate initial session keys when setting up a new validator on cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Polkadot:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/polkadot/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/polkadot/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - Polkadot RPC Method

# author_submitAndWatchExtrinsic - Polkadot RPC Method

Submits a signed extrinsic to Polkadot and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on Polkadot
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-polkadot.n.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-polkadot.n.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/polkadot/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/polkadot/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/polkadot/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - Polkadot RPC Method

# author_submitExtrinsic - Polkadot RPC Method

Submits a fully signed extrinsic to Polkadot for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`author_submitExtrinsic` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Token Transfers** -- Send native tokens or assets between accounts on Polkadot
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-polkadot.n.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/polkadot/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/polkadot/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - Polkadot RPC Method

# beefy_getFinalizedHead - Polkadot RPC Method

Returns the block hash of the latest BEEFY-finalized block on Polkadot. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`beefy_getFinalizedHead` is important for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/polkadot/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - Polkadot RPC Method

# chain_getBlock - Polkadot RPC Method

Retrieves complete block information from Polkadot, including the block header, extrinsics, and justifications.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/polkadot/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/polkadot/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - Polkadot RPC Method

# chain_getBlockHash - Polkadot RPC Method

Returns the block hash for a given block number on Polkadot. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`chain_getBlockHash` is fundamental for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on Polkadot
- **Block Navigation** - Navigate the blockchain history for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on Polkadot
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on Polkadot for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query Polkadot state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct Polkadot network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/polkadot/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - Polkadot RPC Method

# chain_getFinalizedHead - Polkadot RPC Method

Returns the hash of the last finalized block on Polkadot. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`chain_getFinalizedHead` is critical for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on Polkadot
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on Polkadot:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/polkadot/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/polkadot/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - Polkadot RPC Method

# chain_getHeader - Polkadot RPC Method

Returns the block header for a given hash on Polkadot. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`chain_getHeader` is ideal for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on Polkadot
- **Chain Synchronization** - Track block production and monitor chain progress for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on Polkadot:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the Polkadot chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor Polkadot block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/polkadot/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - Polkadot RPC Method

# chain_subscribeFinalizedHeads - Polkadot RPC Method

Subscribe to receive notifications when blocks are finalized on Polkadot. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Exchange Deposits** - Only credit funds after finalization for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-polkadot.n.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-polkadot.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on Polkadot:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/polkadot/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - Polkadot RPC Method

# chain_subscribeNewHeads - Polkadot RPC Method

Subscribe to receive notifications when new block headers are produced on Polkadot. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`chain_subscribeNewHeads` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Block Monitoring** - Track new blocks in real time on Polkadot for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-polkadot.n.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-polkadot.n.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on Polkadot as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on Polkadot:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/polkadot/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/polkadot/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - Polkadot RPC Method

# grandpa_roundState - Polkadot RPC Method

Returns the state of the current GRANDPA finality round on Polkadot when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`grandpa_roundState` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on Polkadot, critical for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/polkadot/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/polkadot/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - Polkadot RPC Method

# payment_queryFeeDetails - Polkadot RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on Polkadot. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`payment_queryFeeDetails` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on Polkadot
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY), showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/polkadot/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/polkadot/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/polkadot/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/polkadot/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - Polkadot RPC Method

# payment_queryInfo - Polkadot RPC Method

Estimates the fee for an encoded extrinsic on Polkadot. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`payment_queryInfo` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Fee Display** -- Show users the estimated transaction cost before they sign on Polkadot
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/polkadot/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/polkadot/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/polkadot/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/polkadot/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - Polkadot RPC Method

# rpc_methods - Polkadot RPC Method

Returns a list of all RPC methods exposed by the Polkadot node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`rpc_methods` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a Polkadot node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a Polkadot endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two Polkadot endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/polkadot/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/polkadot/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - Polkadot RPC Method

# state_call - Polkadot RPC Method

Calls a runtime API function on Polkadot and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_call` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/polkadot/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/polkadot/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/polkadot/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) -- Get the node version for compatibility checking

---

## state_getKeysPaged - Polkadot RPC Method

# state_getKeysPaged - Polkadot RPC Method

Returns storage keys matching a prefix with cursor-based pagination on Polkadot. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_getKeysPaged` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on Polkadot
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-polkadot.n.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/polkadot/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/polkadot/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - Polkadot RPC Method

# state_getMetadata - Polkadot RPC Method

Returns the runtime metadata for Polkadot as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_getMetadata` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on Polkadot
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on Polkadot:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on Polkadot:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/polkadot/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/polkadot/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - Polkadot RPC Method

# state_getRuntimeVersion - Polkadot RPC Method

Returns the runtime version information for Polkadot, including the spec name, spec version, implementation version, and supported API versions.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_getRuntimeVersion` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Version Checking** - Verify runtime compatibility before constructing transactions on Polkadot
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on Polkadot in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/polkadot/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - Polkadot RPC Method

# state_getStorage - Polkadot RPC Method

Returns the SCALE-encoded storage value for a given key on Polkadot. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_getStorage` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on Polkadot
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/polkadot/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/polkadot/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - Polkadot RPC Method

# state_queryStorageAt - Polkadot RPC Method

Queries multiple storage keys at a specific block on Polkadot, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_queryStorageAt` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on Polkadot
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/polkadot/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/polkadot/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/polkadot/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/polkadot/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - Polkadot RPC Method

# system_chain - Polkadot RPC Method

Returns the chain name of the Polkadot network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`system_chain` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Network Verification** -- Confirm your application is connected to the correct Polkadot network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', 'Polkadot');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/polkadot/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/polkadot/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/polkadot/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/polkadot/rpc_methods) -- List all available RPC methods

---

## system_health - Polkadot RPC Method

# system_health - Polkadot RPC Method

Returns the health status of the Polkadot node, including peer count, sync state, and whether the node expects to have peers.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`system_health` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Health Checks** - Monitor node availability and readiness before routing traffic on Polkadot
- **Load Balancing** - Route requests only to healthy, fully synced nodes for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-polkadot.n.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-polkadot.n.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on Polkadot:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy Polkadot nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-polkadot.n.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/polkadot/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - Polkadot RPC Method

# system_name - Polkadot RPC Method

Returns the node implementation name on Polkadot. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`system_name` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on Polkadot
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('Polkadot node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Polkadot node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'Polkadot node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'Polkadot node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Polkadot node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of Polkadot nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/polkadot/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/polkadot/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/polkadot/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/polkadot/rpc_methods) -- List all available RPC methods

---

## system_properties - Polkadot RPC Method

# system_properties - Polkadot RPC Method

Returns the chain-specific properties for Polkadot, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`system_properties` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on Polkadot
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/polkadot/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/polkadot/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/polkadot/rpc_methods) -- List all available RPC methods

---

## system_version - Polkadot RPC Method

# system_version - Polkadot RPC Method

Returns the node implementation version string on Polkadot. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`system_version` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on Polkadot
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('Polkadot node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Polkadot node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'Polkadot node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'Polkadot node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Polkadot node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple Polkadot nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/polkadot/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/polkadot/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/polkadot/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/polkadot/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/polkadot/rpc_methods) -- List all available RPC methods

---

## Polygon - Ethereum Layer 2

# Polygon - Ethereum Layer 2

## Polygon RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Polygon supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Polygon?

Polygon is a leading Ethereum scaling solution, providing a framework for building and connecting Ethereum-compatible blockchain networks. Built with Proof of Stake consensus, Polygon offers:

### **Lightning Fast Performance**

- **2 second block times** - Fast transaction confirmations
- **Up to 65,000 TPS** - Massive throughput capacity
- **$0.01 average transaction cost** - 10,000x cheaper than Ethereum

### **Enterprise Security**

- **100+ validators** - Highly decentralized network
- **$2B+ staked** - Strong economic security
- **Battle-tested since 2020** - Processing billions of transactions

### **Massive Ecosystem**

- **50M+ unique addresses** - One of the largest L2 user bases
- **7,000+ dApps** - Comprehensive DeFi, Gaming, and NFT ecosystem
- **Major integrations** - Aave, Uniswap, OpenSea, Chainlink

## Quick Start with Polygon

Connect to Polygon in seconds with Dwellir's optimized endpoints:

### Installation & Setup

ethers.js v6
web3.js
viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Polygon via Dwellir
const provider = new JsonRpcProvider(
  'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Test connection
const blockNumber = await provider.getBlockNumber();
console.log('Connected to Polygon at block:', blockNumber);
```

```javascript
import Web3 from 'web3';

// Initialize Web3 with Dwellir endpoint
const web3 = new Web3(
  'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Polygon (Chain ID:', chainId, ')');
```

```typescript
import { createPublicClient, http } from 'viem';
import { polygon } from 'viem/chains';

const client = createPublicClient({
  chain: polygon,
  transport: http('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'),
});

const blockNumber = await client.getBlockNumber();
console.log('Current block:', blockNumber);
```

## Available Methods

### Core JSON-RPC Methods

Essential methods for interacting with the Polygon network:

| Method                      | Description                           | Link                                                 |
| --------------------------- | ------------------------------------- | ---------------------------------------------------- |
| `eth_blockNumber`           | Get the latest block number           | [View docs](https://www.dwellir.com/docs/polygon/eth_blockNumber)           |
| `eth_getBalance`            | Query MATIC/POL balance of an address | [View docs](https://www.dwellir.com/docs/polygon/eth_getBalance)            |
| `eth_getBlockByNumber`      | Retrieve block details by number      | [View docs](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber)      |
| `eth_call`                  | Execute smart contract calls          | [View docs](https://www.dwellir.com/docs/polygon/eth_call)                  |
| `eth_getTransactionByHash`  | Get transaction details               | [View docs](https://www.dwellir.com/docs/polygon/eth_getTransactionByHash)  |
| `eth_getTransactionReceipt` | Fetch transaction receipts            | [View docs](https://www.dwellir.com/docs/polygon/eth_getTransactionReceipt) |
| `eth_sendRawTransaction`    | Broadcast signed transactions         | [View docs](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction)    |
| `eth_estimateGas`           | Estimate gas for transactions         | [View docs](https://www.dwellir.com/docs/polygon/eth_estimateGas)           |
| `eth_gasPrice`              | Get current gas price                 | [View docs](https://www.dwellir.com/docs/polygon/eth_gasPrice)              |
| `eth_getLogs`               | Query event logs                      | [View docs](https://www.dwellir.com/docs/polygon/eth_getLogs)               |

### Debug & Trace Methods

Advanced methods for debugging and analyzing transactions:

| Method                     | Description                          | Link                                                |
| -------------------------- | ------------------------------------ | --------------------------------------------------- |
| `debug_traceTransaction`   | Detailed transaction execution trace | [View docs](https://www.dwellir.com/docs/polygon/debug_traceTransaction)   |
| `debug_traceBlock`         | Trace all transactions in a block    | [View docs](https://www.dwellir.com/docs/polygon/debug_traceBlock)         |
| `debug_traceBlockByNumber` | Trace block by number                | [View docs](https://www.dwellir.com/docs/polygon/debug_traceBlockByNumber) |

## Network Information

### Chain Details

| Parameter           | Mainnet                                          | Testnet (Amoy)                           |
| ------------------- | ------------------------------------------------ | ---------------------------------------- |
| **Chain ID**        | 137                                              | 80002                                    |
| **Currency**        | MATIC (transitioning to POL)                     | MATIC                                    |
| **Block Time**      | \~2 seconds                                      | \~2 seconds                              |
| **Block Gas Limit** | 30M                                              | 30M                                      |
| **RPC Endpoint**    | `https://api-polygon-mainnet-full.n.dwellir.com` | `https://api-polygon-amoy.n.dwellir.com` |

### Important Addresses

| Contract       | Address                                      |
| -------------- | -------------------------------------------- |
| **WMATIC**     | `0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270` |
| **USDC**       | `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174` |
| **USDT**       | `0xc2132D05D31c914a87C6611C10748AEb04B58e8F` |
| **Multicall3** | `0xcA11bde05977b3631167028862bE2a173976CA11` |

## Best Practices

### 1. **Optimize Gas Usage**

Polygon has low fees, but optimizing gas usage is still important:

```javascript
// Use gas estimation for accurate pricing
const gasEstimate = await contract.estimateGas.transfer(to, amount);
const gasPrice = await provider.getGasPrice();
const txCost = gasEstimate * gasPrice;
```

### 2. **Handle Network Congestion**

Monitor and adapt to network conditions:

```javascript
// Implement dynamic gas pricing
const gasPrice = await provider.getGasPrice();
const adjustedGasPrice = gasPrice * 110n / 100n; // 10% buffer
```

### 3. **Leverage Polygon's Speed**

Take advantage of fast block times for better UX:

```javascript
// Quick confirmation monitoring
const tx = await wallet.sendTransaction(transaction);
const receipt = await tx.wait(1); // Usually confirms in 1 block (~2 seconds)
```

## Resources

- [Official Polygon Documentation](https://docs.polygon.technology/)
- [Polygon Network Explorer](https://polygonscan.com/)
- [Polygon Developer Portal](https://polygon.technology/developers)
- [Get Your Dwellir API Key](https://dashboard.dwellir.com)

## Support

Need help? Our team is available 24/7:

- **Email**: <support@dwellir.com>
- **Documentation**: You're already here!

Start building on Polygon with Dwellir's enterprise-grade infrastructure today.

---

## bor_getRootHash - Get checkpoint root hash

# bor_getRootHash - Get checkpoint root hash

Get checkpoint root hash on the Polygon network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "bor_getRootHash",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "bor_getRootHash",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'bor_getRootHash',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## bor_getSigners - Get current validator set

# bor_getSigners - Get current validator set

Get current validator set on the Polygon network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "bor_getSigners",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "bor_getSigners",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'bor_getSigners',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## debug_traceBlock - Polygon RPC Method

# debug_traceBlock - Polygon RPC Method

Traces all transactions in a block on Polygon by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Polygon - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Polygon
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Polygon:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Polygon blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/polygon/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/polygon/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/polygon/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/polygon/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Polygon RPC Method

# debug_traceBlockByHash - Polygon RPC Method

Traces all transactions in a block on Polygon identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Polygon - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Polygon
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Polygon:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Polygon:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/polygon/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/polygon/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/polygon/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/polygon/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/polygon/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Polygon RPC Method

# debug_traceBlockByNumber - Polygon RPC Method

Traces all transactions in a block on Polygon identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Polygon - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Polygon execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Polygon:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Polygon:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/polygon/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/polygon/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/polygon/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/polygon/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Polygon RPC Method

# debug_traceCall - Polygon RPC Method

Traces a call on Polygon without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Polygon - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Polygon
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "data": "0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
        "data": "0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
        "data": "0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    data: '0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    data: '0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    'data': '0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
        "data": "0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Polygon to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Polygon:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Polygon:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/polygon/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/polygon/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/polygon/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/polygon/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Polygon RPC Method

# debug_traceTransaction - Polygon RPC Method

Traces a transaction execution on Polygon by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Polygon
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/polygon/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/polygon/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Polygon RPC Method

# eth_accounts - Polygon RPC Method

Returns a list of addresses owned by the client on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for enterprise developers, gaming studios, and teams building high-throughput applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/polygon/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/polygon/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Polygon RPC Method

# eth_blockNumber - Polygon RPC Method

Returns the number of the most recent block on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_blockNumber` is fundamental for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Syncing Applications** - Keep your dApp in sync with the latest Polygon blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Polygon block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Polygon block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Polygon block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Polygon block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Polygon block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Polygon:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Polygon:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Polygon node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/polygon/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/polygon/eth_syncing) - Check if node is still syncing

---

## eth_call - Polygon RPC Method

# eth_call - Polygon RPC Method

Executes a new message call immediately without creating a transaction on Polygon. Used for reading smart contract state.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

The `eth_call` method serves these key scenarios for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Polygon
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';
const walletAddress = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Polygon. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Polygon
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Polygon

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "data": "0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "data": "0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    data := common.FromHex("0x70a082310000000000000000000000008D97689C9818892B700e27F316cc3E41e17fBeb9")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Polygon RPC Method

# eth_chainId - Polygon RPC Method

Returns the chain ID used for transaction signing on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_chainId` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/polygon/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/polygon/eth_syncing) - Check sync status

---

## eth_coinbase - Polygon RPC Method

# eth_coinbase - Polygon RPC Method

Checks the legacy `eth_coinbase` compatibility method on Polygon. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for enterprise developers, gaming studios, and teams building high-throughput applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Polygon coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Polygon coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Polygon coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Polygon coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Polygon coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Polygon nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/polygon/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/polygon/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/polygon/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Polygon RPC Method

# eth_estimateGas - Polygon RPC Method

Estimates the gas necessary to execute a transaction on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Polygon
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x8D97689C9818892B700e27F316cc3E41e17fBeb9', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x8D97689C9818892B700e27F316cc3E41e17fBeb9', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Polygon.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Polygon may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "to": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x8D97689C9818892B700e27F316cc3E41e17fBeb9', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/polygon/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Polygon RPC Method

# eth_feeHistory - Polygon RPC Method

Returns historical gas fee data on Polygon, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Polygon without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Polygon.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Polygon) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/polygon/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/polygon/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Polygon RPC Method

# eth_gasPrice - Polygon RPC Method

Returns the current gas price on Polygon in wei.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Polygon
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Polygon. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Polygon, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Polygon: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Polygon supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/polygon/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/polygon/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Polygon RPC Method

# eth_getBalance - Polygon RPC Method

Returns the balance of a given address on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getBalance` is fundamental for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Polygon
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Polygon
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Polygon. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Polygon`);
  return balance;
}

displayBalance('0x8D97689C9818892B700e27F316cc3E41e17fBeb9');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Polygon at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Polygon')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Polygon')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Polygon.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/polygon/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/polygon/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Polygon RPC Method

# eth_getBlockByHash - Polygon RPC Method

Returns information about a block by hash on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getBlockByHash` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Polygon
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Polygon.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Polygon.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Polygon RPC Method

# eth_getBlockByNumber - Polygon RPC Method

Returns information about a block by block number on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getBlockByNumber` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Polygon
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Polygon with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Polygon. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/polygon/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/polygon/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Polygon RPC Method

# eth_getBlockReceipts - Polygon RPC Method

Returns all transaction receipts for a block on Polygon. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getBlockReceipts` is useful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Polygon, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Polygon. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf3425ff44ecaa4066e2f88ea1873e8c7adeb21db3765b9af80a577b35b5eed32",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/polygon/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/polygon/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Polygon RPC Method

# eth_getCode - Polygon RPC Method

Returns the bytecode at a given address on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getCode` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Polygon
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Polygon:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Polygon:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/polygon/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/polygon/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Polygon RPC Method

# eth_getFilterChanges - Polygon RPC Method

Polls a filter on Polygon for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getFilterChanges` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Polygon
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Polygon:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/polygon/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/polygon/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/polygon/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/polygon/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/polygon/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Polygon RPC Method

# eth_getFilterLogs - Polygon RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Polygon. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getFilterLogs` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Polygon
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/polygon/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/polygon/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/polygon/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/polygon/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Polygon RPC Method

# eth_getLogs - Polygon RPC Method

Returns an array of all logs matching a given filter object on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Polygon for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Polygon
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Polygon.

```javascript
const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Polygon enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Polygon, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/polygon/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/polygon/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Polygon RPC Method

# eth_getStorageAt - Polygon RPC Method

Returns the value from a storage position at a given address on Polygon. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getStorageAt` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **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 enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **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": [
    "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "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-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x8D97689C9818892B700e27F316cc3E41e17fBeb9', '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-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';

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-polygon-mainnet-full.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 = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
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-polygon-mainnet-full.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-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    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 Polygon:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.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-polygon-mainnet-full.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 = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';
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 Polygon:`);
  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/polygon/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/polygon/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/polygon/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Polygon RPC Method

# eth_getTransactionByHash - Polygon RPC Method

Returns the information about a transaction by transaction hash on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getTransactionByHash` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Polygon
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Polygon. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Polygon. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/polygon/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Polygon RPC Method

# eth_getTransactionCount - Polygon RPC Method

Returns the number of transactions sent from an address on Polygon, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getTransactionCount` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Polygon
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x8D97689C9818892B700e27F316cc3E41e17fBeb9', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Polygon nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9'
nonce = get_transaction_count(address)
print(f'Polygon nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Polygon nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Polygon:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x8D97689C9818892B700e27F316cc3E41e17fBeb9');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/polygon/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/polygon/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/polygon/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Polygon RPC Method

# eth_getTransactionReceipt - Polygon RPC Method

Returns the receipt of a transaction by transaction hash on Polygon. Receipt is only available for mined transactions.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_getTransactionReceipt` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Polygon and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Polygon. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Polygon, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x1c9191ff3b87e14cc8f0e3b4081ba4ab42c12bb1153954c33298f3ecf7beab05")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/polygon/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/polygon/eth_getLogs) - Query logs by filter

---

## eth_getTransactionReceiptsByBlock - Get all...

# eth_getTransactionReceiptsByBlock - Get all...

Get all receipts in block on the Polygon network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_getTransactionReceiptsByBlock",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceiptsByBlock",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionReceiptsByBlock',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_hashrate - Polygon RPC Method

# eth_hashrate - Polygon RPC Method

Returns the legacy `eth_hashrate` compatibility value on Polygon. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Polygon hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Polygon hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Polygon hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Polygon hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Polygon hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/polygon/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/polygon/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Polygon RPC Method

# eth_maxPriorityFeePerGas - Polygon RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Polygon. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Polygon
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Polygon priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Polygon priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Polygon priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Polygon:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Polygon:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/polygon/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/polygon/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/polygon/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Polygon RPC Method

# eth_mining - Polygon RPC Method

Checks the legacy `eth_mining` compatibility method on Polygon. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Polygon mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Polygon mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Polygon mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Polygon mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Polygon mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/polygon/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/polygon/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Polygon RPC Method

# eth_newBlockFilter - Polygon RPC Method

Creates a filter on Polygon that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_newBlockFilter` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Block Monitoring** - Detect new blocks on Polygon as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Polygon:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/polygon/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/polygon/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/polygon/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Polygon RPC Method

# eth_newFilter - Polygon RPC Method

Creates a filter object on Polygon based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_newFilter` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Event Monitoring** - Subscribe to specific contract events on Polygon such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Polygon:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x8D97689C9818892B700e27F316cc3E41e17fBeb9',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/polygon/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/polygon/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/polygon/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/polygon/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/polygon/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Polygon RPC Method

# eth_newPendingTransactionFilter - Polygon RPC Method

Creates a filter on Polygon that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on Polygon to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for enterprise solutions (Starbucks, Disney, Reddit), gaming, DeFi, and stablecoin payments

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Polygon...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Polygon:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/polygon/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/polygon/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/polygon/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Polygon RPC Method

# eth_protocolVersion - Polygon RPC Method

Returns the current Ethereum protocol version used by the Polygon node.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_protocolVersion` is useful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Polygon protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Polygon protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Polygon protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Polygon protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Polygon protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Polygon nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/polygon/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/polygon/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/polygon/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Polygon RPC Method

# eth_sendRawTransaction - Polygon RPC Method

Submits a pre-signed transaction for broadcast to Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Polygon
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x8D97689C9818892B700e27F316cc3E41e17fBeb9', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Polygon mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/polygon/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x8D97689C9818892B700e27F316cc3E41e17fBeb9")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/polygon/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/polygon/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Polygon RPC Method

# eth_sendTransaction - Polygon RPC Method

Creates and sends a new transaction from an unlocked account on Polygon. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for enterprise developers, gaming studios, and teams building high-throughput applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Polygon tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Polygon tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Polygon tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Polygon tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Polygon tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Polygon dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/polygon/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/polygon/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Polygon RPC Method

# eth_signTransaction - Polygon RPC Method

Signs a transaction with the private key of the specified account on Polygon without submitting it to the network.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for enterprise developers, gaming studios, and teams building high-throughput applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Polygon tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Polygon tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Polygon tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Polygon:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/polygon/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/polygon/eth_accounts) - List accounts available for signing

---

## eth_syncing - Polygon RPC Method

# eth_syncing - Polygon RPC Method

Returns the sync status of your Polygon node - either `false` when fully synced, or an object describing the sync progress.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_syncing` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Polygon node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Polygon node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Polygon node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/polygon/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/polygon/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/polygon/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Polygon RPC Method

# eth_uninstallFilter - Polygon RPC Method

Removes a filter on Polygon that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`eth_uninstallFilter` is important for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/polygon/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/polygon/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/polygon/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/polygon/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/polygon/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Polygon RPC Method

# net_listening - Polygon RPC Method

Checks whether the connected Polygon client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`net_listening` is useful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Polygon node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Polygon node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Polygon node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/polygon/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/polygon/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/polygon/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/polygon/web3_clientVersion) - Get node client info

---

## net_peerCount - Polygon RPC Method

# net_peerCount - Polygon RPC Method

Returns the number of peers currently connected to your Polygon node.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`net_peerCount` is important for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Polygon deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Polygon peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Polygon peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Polygon peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Polygon nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/polygon/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/polygon/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/polygon/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/polygon/web3_clientVersion) - Get node client info

---

## net_version - Polygon RPC Method

# net_version - Polygon RPC Method

Returns the current network ID on Polygon as a decimal string. The network ID identifies which network the node is connected to.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`net_version` is essential for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Endpoint Identification** - Confirm your application is connected to the expected Polygon network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Polygon network ID:', networkId);

// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Polygon network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Polygon network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/polygon/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/polygon/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/polygon/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/polygon/eth_syncing) - Check node sync progress

---

## rpc_modules - Polygon RPC Method

# rpc_modules - Polygon RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Polygon endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`rpc_modules` is useful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/polygon/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/polygon/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Polygon RPC Method

# txpool_content - Polygon RPC Method

Returns the full pending and queued transaction pool for the connected Polygon endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`txpool_content` is useful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/polygon/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/polygon/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/polygon/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Polygon RPC Method

# txpool_status - Polygon RPC Method

Returns transaction pool counters for the connected Polygon endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`txpool_status` is valuable for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/polygon/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/polygon/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/polygon/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Polygon RPC Method

# web3_clientVersion - Polygon RPC Method

Returns the current client software version string for your Polygon node, including the client name, version number, OS, and runtime.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

## When to Use This Method

`web3_clientVersion` is valuable for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Polygon client:', clientVersion);

// Using fetch
const response = await fetch('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Polygon client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Polygon client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/polygon/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/polygon/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/polygon/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/polygon/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Polygon RPC Method

# web3_sha3 - Polygon RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Polygon.

> **Why Polygon?** Build on the most adopted Ethereum scaling solution with 45,000+ dApps and enterprise partnerships with $4B+ TVL, sub-$0.01 transactions, 8M+ daily transactions, and zkEVM for enhanced security.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for enterprise developers, gaming studios, and teams building high-throughput applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-polygon-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/polygon/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/polygon/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/polygon/web3_clientVersion) - Get node client version

---

## PulseChain - EVM Layer 1 Documentation

# PulseChain - EVM Layer 1 Documentation

## PulseChain RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where PulseChain supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on PulseChain?

PulseChain is an EVM-compatible Layer 1 blockchain offering low transaction fees and energy-efficient Proof-of-Stake consensus. It features a full-state fork of Ethereum with native token duplication:

### **High Performance**

- **3-second block times** - Fast transaction confirmations
- **4x higher throughput** than Ethereum
- **Low gas fees** - Significantly cheaper than Ethereum mainnet

### **Robust Security**

- **Proof-of-Stake consensus** - Energy-efficient validation
- **33 rotating validators** - Decentralized network security
- **Slashing mechanisms** - Economic security guarantees

### **Growing Ecosystem**

- **Full Ethereum fork** - All Ethereum state duplicated at launch
- **Native asset duplication** - PRC-20 token system
- **EVM compatibility** - Seamless migration for Ethereum dApps

## Quick Start with PulseChain

Connect to PulseChain in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to PulseChain mainnet
const provider = new JsonRpcProvider(
  'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to PulseChain mainnet
const web3 = new Web3(
  'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to PulseChain:', chainId === 369);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { pulsechain } from 'viem/chains';

// Create PulseChain client
const client = createPublicClient({
  chain: pulsechain,
  transport: http('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 369       | Mainnet      |
| Block Time   | 3 seconds | Average      |
| Gas Token    | PLS       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

PulseChain supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods for EVM-compatible development.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Check transaction status
  if (receipt.status === 1) {
    console.log('Transaction successful');
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on PulseChain:

```javascript
// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Get current gas price
const gasPrice = await provider.getGasPrice();

// Calculate total cost in PLS
const totalCost = gasEstimate * gasPrice;
console.log('Transaction cost:', totalCost.toString(), 'PLS');
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // PulseChain recommended batch size
  const currentBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class PulseChainProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for gas"

PulseChain transactions require PLS for gas fees:

```javascript
// Check balance before sending transaction
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more PLS`);
}
```

### Error: "Transaction underpriced"

PulseChain uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from Ethereum to PulseChain requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (PulseChain)
const provider = new JsonRpcProvider(
  'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (369)
// Note: PLS gas token instead of ETH
// Note: Separate block numbers
```

## Resources & Tools

### Official Resources

- [PulseChain Website](https://pulsechain.com)
- [PulseChain Bridge](https://bridge.pulsechain.com)
- [PulseChain Explorer](https://scan.pulsechain.com)

### Developer Tools

- [Hardhat Config](https://hexikani.github.io/pulsechain-docs/hardhat-development.html)
- [Foundry Setup](https://hexikani.github.io/pulsechain-docs/)
- [PulseX DEX](https://pulsex.com)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Top 6 PulseChain RPC Providers 2026](https://www.dwellir.com/blog/best-pulsechain-rpc-providers)

***

*Start building on PulseChain with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Pulsechain RPC Method

# debug_traceBlock - Pulsechain RPC Method

Traces all transactions in a block on Pulsechain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Pulsechain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Pulsechain
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Pulsechain:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Pulsechain blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/pulsechain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/pulsechain/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Pulsechain RPC Method

# debug_traceBlockByHash - Pulsechain RPC Method

Traces all transactions in a block on Pulsechain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Pulsechain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Pulsechain
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Pulsechain:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Pulsechain:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/pulsechain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/pulsechain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/pulsechain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Pulsechain RPC Method

# debug_traceBlockByNumber - Pulsechain RPC Method

Traces all transactions in a block on Pulsechain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Pulsechain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Pulsechain execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Pulsechain:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Pulsechain:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/pulsechain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/pulsechain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/pulsechain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Pulsechain RPC Method

# debug_traceCall - Pulsechain RPC Method

Traces a call on Pulsechain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Pulsechain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Pulsechain
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "data": "0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
        "data": "0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
        "data": "0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    data: '0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    data: '0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    'data': '0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
        "data": "0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Pulsechain to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Pulsechain:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Pulsechain:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/pulsechain/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/pulsechain/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Pulsechain RPC Method

# debug_traceTransaction - Pulsechain RPC Method

Traces a transaction execution on Pulsechain by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Pulsechain
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/pulsechain/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/pulsechain/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Pulsechain RPC Method

# eth_accounts - Pulsechain RPC Method

Returns a list of addresses owned by the client on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, staking protocol builders, and teams migrating from Ethereum in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/pulsechain/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Pulsechain RPC Method

# eth_blockNumber - Pulsechain RPC Method

Returns the number of the most recent block on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Syncing Applications** - Keep your dApp in sync with the latest Pulsechain blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Pulsechain block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Pulsechain block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Pulsechain block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Pulsechain block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pulsechain block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Pulsechain:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Pulsechain:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Pulsechain node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/pulsechain/eth_syncing) - Check if node is still syncing

---

## eth_call - Pulsechain RPC Method

# eth_call - Pulsechain RPC Method

Executes a new message call immediately without creating a transaction on Pulsechain. Used for reading smart contract state.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Pulsechain
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';
const walletAddress = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Pulsechain. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Pulsechain
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Pulsechain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "data": "0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "data": "0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    data := common.FromHex("0x70a08231000000000000000000000000A1077a294dDE1B09bB078844df40758a5D0f9a27")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Pulsechain RPC Method

# eth_chainId - Pulsechain RPC Method

Returns the chain ID used for transaction signing on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/pulsechain/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/pulsechain/eth_syncing) - Check sync status

---

## eth_coinbase - Pulsechain RPC Method

# eth_coinbase - Pulsechain RPC Method

Checks the legacy `eth_coinbase` compatibility method on Pulsechain. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, staking protocol builders, and teams migrating from Ethereum when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Pulsechain coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Pulsechain coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Pulsechain coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Pulsechain coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Pulsechain coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Pulsechain nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/pulsechain/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/pulsechain/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/pulsechain/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Pulsechain RPC Method

# eth_estimateGas - Pulsechain RPC Method

Estimates the gas necessary to execute a transaction on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Pulsechain
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xA1077a294dDE1B09bB078844df40758a5D0f9a27', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xA1077a294dDE1B09bB078844df40758a5D0f9a27', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Pulsechain.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Pulsechain may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "to": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xA1077a294dDE1B09bB078844df40758a5D0f9a27', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/pulsechain/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Pulsechain RPC Method

# eth_feeHistory - Pulsechain RPC Method

Returns historical gas fee data on Pulsechain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Pulsechain without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Pulsechain.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Pulsechain) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/pulsechain/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/pulsechain/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Pulsechain RPC Method

# eth_gasPrice - Pulsechain RPC Method

Returns the current gas price on Pulsechain in wei.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Pulsechain
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Pulsechain. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Pulsechain, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Pulsechain: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Pulsechain supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/pulsechain/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/pulsechain/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Pulsechain RPC Method

# eth_getBalance - Pulsechain RPC Method

Returns the balance of a given address on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Pulsechain
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Pulsechain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Pulsechain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Pulsechain`);
  return balance;
}

displayBalance('0xA1077a294dDE1B09bB078844df40758a5D0f9a27');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Pulsechain at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Pulsechain')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Pulsechain')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Pulsechain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/pulsechain/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Pulsechain RPC Method

# eth_getBlockByHash - Pulsechain RPC Method

Returns information about a block by hash on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Pulsechain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Pulsechain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Pulsechain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/pulsechain/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Pulsechain RPC Method

# eth_getBlockByNumber - Pulsechain RPC Method

Returns information about a block by block number on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Pulsechain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Pulsechain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Pulsechain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/pulsechain/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Pulsechain RPC Method

# eth_getBlockReceipts - Pulsechain RPC Method

Returns all transaction receipts for a block on Pulsechain. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Pulsechain, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Pulsechain. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x6f593d6cf3e5a475798567e4defeef46367cdc22556d310bd39bb8f23bdd8f52",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Pulsechain RPC Method

# eth_getCode - Pulsechain RPC Method

Returns the bytecode at a given address on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Pulsechain
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Pulsechain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Pulsechain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/pulsechain/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/pulsechain/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Pulsechain RPC Method

# eth_getFilterChanges - Pulsechain RPC Method

Polls a filter on Pulsechain for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Pulsechain
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Pulsechain:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/pulsechain/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/pulsechain/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/pulsechain/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/pulsechain/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/pulsechain/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Pulsechain RPC Method

# eth_getFilterLogs - Pulsechain RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Pulsechain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Pulsechain
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/pulsechain/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/pulsechain/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/pulsechain/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/pulsechain/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Pulsechain RPC Method

# eth_getLogs - Pulsechain RPC Method

Returns an array of all logs matching a given filter object on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Pulsechain for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Pulsechain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Pulsechain.

```javascript
const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Pulsechain enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Pulsechain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/pulsechain/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/pulsechain/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Pulsechain RPC Method

# eth_getStorageAt - Pulsechain RPC Method

Returns the value from a storage position at a given address on Pulsechain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **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 low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **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": [
    "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "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-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xA1077a294dDE1B09bB078844df40758a5D0f9a27', '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-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';

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-pulse-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 = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
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-pulse-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-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    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 Pulsechain:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-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-pulse-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 = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';
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 Pulsechain:`);
  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/pulsechain/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/pulsechain/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/pulsechain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Pulsechain RPC Method

# eth_getTransactionByHash - Pulsechain RPC Method

Returns the information about a transaction by transaction hash on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Pulsechain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Pulsechain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Pulsechain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Pulsechain RPC Method

# eth_getTransactionCount - Pulsechain RPC Method

Returns the number of transactions sent from an address on Pulsechain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Pulsechain
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xA1077a294dDE1B09bB078844df40758a5D0f9a27', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Pulsechain nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xA1077a294dDE1B09bB078844df40758a5D0f9a27'
nonce = get_transaction_count(address)
print(f'Pulsechain nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pulsechain nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Pulsechain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xA1077a294dDE1B09bB078844df40758a5D0f9a27');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/pulsechain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Pulsechain RPC Method

# eth_getTransactionReceipt - Pulsechain RPC Method

Returns the receipt of a transaction by transaction hash on Pulsechain. Receipt is only available for mined transactions.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Pulsechain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Pulsechain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Pulsechain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xd9692b0cd832e24983260081d2a6d4862f835466650322101e7b1a3f57cefe25")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/pulsechain/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Pulsechain RPC Method

# eth_hashrate - Pulsechain RPC Method

Returns the legacy `eth_hashrate` compatibility value on Pulsechain. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Pulsechain hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Pulsechain hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Pulsechain hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Pulsechain hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Pulsechain hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/pulsechain/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/pulsechain/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/pulsechain/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Pulsechain RPC Method

# eth_maxPriorityFeePerGas - Pulsechain RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Pulsechain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Pulsechain
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Pulsechain priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Pulsechain priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Pulsechain priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Pulsechain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Pulsechain:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/pulsechain/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/pulsechain/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Pulsechain RPC Method

# eth_mining - Pulsechain RPC Method

Checks the legacy `eth_mining` compatibility method on Pulsechain. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Pulsechain mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Pulsechain mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Pulsechain mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Pulsechain mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Pulsechain mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/pulsechain/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/pulsechain/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/pulsechain/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Pulsechain RPC Method

# eth_newBlockFilter - Pulsechain RPC Method

Creates a filter on Pulsechain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Block Monitoring** - Detect new blocks on Pulsechain as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Pulsechain:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/pulsechain/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/pulsechain/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/pulsechain/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/pulsechain/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Pulsechain RPC Method

# eth_newFilter - Pulsechain RPC Method

Creates a filter object on Pulsechain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Event Monitoring** - Subscribe to specific contract events on Pulsechain such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xA1077a294dDE1B09bB078844df40758a5D0f9a27",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Pulsechain:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xA1077a294dDE1B09bB078844df40758a5D0f9a27',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/pulsechain/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/pulsechain/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/pulsechain/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/pulsechain/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/pulsechain/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Pulsechain RPC Method

# eth_newPendingTransactionFilter - Pulsechain RPC Method

Creates a filter on Pulsechain that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Mempool Monitoring** - Observe unconfirmed transactions on Pulsechain to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for low-cost DeFi, staking protocols, and Ethereum-compatible dApps with reduced fees

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Pulsechain...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Pulsechain:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/pulsechain/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/pulsechain/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Pulsechain RPC Method

# eth_protocolVersion - Pulsechain RPC Method

Returns the current Ethereum protocol version used by the Pulsechain node.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Pulsechain protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Pulsechain protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Pulsechain protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Pulsechain protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pulsechain protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Pulsechain nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/pulsechain/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/pulsechain/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/pulsechain/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Pulsechain RPC Method

# eth_sendRawTransaction - Pulsechain RPC Method

Submits a pre-signed transaction for broadcast to Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Pulsechain
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xA1077a294dDE1B09bB078844df40758a5D0f9a27', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Pulsechain mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/pulsechain/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xA1077a294dDE1B09bB078844df40758a5D0f9a27")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/pulsechain/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/pulsechain/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Pulsechain RPC Method

# eth_sendTransaction - Pulsechain RPC Method

Creates and sends a new transaction from an unlocked account on Pulsechain. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, staking protocol builders, and teams migrating from Ethereum in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Pulsechain tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Pulsechain tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Pulsechain tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Pulsechain tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pulsechain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Pulsechain dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/pulsechain/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/pulsechain/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Pulsechain RPC Method

# eth_signTransaction - Pulsechain RPC Method

Signs a transaction with the private key of the specified account on Pulsechain without submitting it to the network.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, staking protocol builders, and teams migrating from Ethereum in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Pulsechain tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Pulsechain tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Pulsechain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Pulsechain:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/pulsechain/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/pulsechain/eth_accounts) - List accounts available for signing

---

## eth_syncing - Pulsechain RPC Method

# eth_syncing - Pulsechain RPC Method

Returns the sync status of your Pulsechain node - either `false` when fully synced, or an object describing the sync progress.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Pulsechain node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Pulsechain node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Pulsechain node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/pulsechain/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/pulsechain/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/pulsechain/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/pulsechain/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Pulsechain RPC Method

# eth_uninstallFilter - Pulsechain RPC Method

Removes a filter on Pulsechain that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/pulsechain/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/pulsechain/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/pulsechain/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/pulsechain/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/pulsechain/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Pulsechain RPC Method

# net_listening - Pulsechain RPC Method

Checks whether the connected Pulsechain client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`net_listening` is useful for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Pulsechain node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Pulsechain node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Pulsechain node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/pulsechain/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/pulsechain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/pulsechain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/pulsechain/web3_clientVersion) - Get node client info

---

## net_peerCount - Pulsechain RPC Method

# net_peerCount - Pulsechain RPC Method

Returns the number of peers currently connected to your Pulsechain node.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`net_peerCount` is important for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Pulsechain deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Pulsechain peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Pulsechain peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Pulsechain peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Pulsechain nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/pulsechain/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/pulsechain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/pulsechain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/pulsechain/web3_clientVersion) - Get node client info

---

## net_version - Pulsechain RPC Method

# net_version - Pulsechain RPC Method

Returns the current network ID on Pulsechain as a decimal string. The network ID identifies which network the node is connected to.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`net_version` is essential for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Endpoint Identification** - Confirm your application is connected to the expected Pulsechain network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Pulsechain network ID:', networkId);

// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Pulsechain network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pulsechain network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/pulsechain/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/pulsechain/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/pulsechain/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/pulsechain/eth_syncing) - Check node sync progress

---

## rpc_modules - Pulsechain RPC Method

# rpc_modules - Pulsechain RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Pulsechain endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/pulsechain/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/pulsechain/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Pulsechain RPC Method

# web3_clientVersion - Pulsechain RPC Method

Returns the current client software version string for your Pulsechain node, including the client name, version number, OS, and runtime.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Pulsechain client:', clientVersion);

// Using fetch
const response = await fetch('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Pulsechain client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pulsechain client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/pulsechain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/pulsechain/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/pulsechain/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/pulsechain/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Pulsechain RPC Method

# web3_sha3 - Pulsechain RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Pulsechain.

> **Why Pulsechain?** Build on the Ethereum fork L1 with lower gas fees and proof-of-stake consensus with full Ethereum state fork, proof-of-stake consensus, lower gas fees than Ethereum mainnet, and PulseX DEX ecosystem.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, staking protocol builders, and teams migrating from Ethereum:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-pulse-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/pulsechain/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/pulsechain/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/pulsechain/web3_clientVersion) - Get node client version

---

## Robinhood Chain RPC: Chain ID 4663, eth_getLogs and WebSocket

# Robinhood Chain RPC: Chain ID 4663, eth_getLogs and WebSocket

## Robinhood RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Robinhood supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Robinhood Chain endpoints and chain facts

| Item                     | Value                                                              |
| ------------------------ | ------------------------------------------------------------------ |
| HTTPS endpoint           | `https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY` |
| WebSocket (WSS) endpoint | `wss://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY`   |
| Chain ID                 | 4663 (`0x1237`)                                                    |
| Block time               | About 0.1 s                                                        |
| Archive state            | Yes                                                                |
| `debug_*` methods        | Yes                                                                |
| `trace_*` methods        | No, use `debug_trace*`                                             |

Every Dwellir endpoint needs an API key. There is no keyless Dwellir endpoint for Robinhood Chain.

The cheapest plan with `eth_getLogs` and WebSocket is Developer at $49/month. It allows 500 blocks per [`eth_getLogs`](https://www.dwellir.com/docs/robinhood/eth_getLogs) request, about 50 seconds of Robinhood Chain blocks. Growth at $299/month raises the range to 10,000 blocks. The Free plan (20 responses per second, 100,000 responses a day) includes HTTPS and WebSocket access but not `eth_getLogs`. The plans section above lists the remaining limits, and [rate limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) has the block-range table for every plan.

Provider pricing for Robinhood Chain is compared in [best Robinhood Chain RPC providers](https://www.dwellir.com/blog/best-robinhood-chain-rpc-providers). For swaps, pool state and Stock Token data, see [how to get Robinhood Chain data for DeFi strategies](https://www.dwellir.com/blog/robinhood-chain-defi-data).

## Why Build on Robinhood Chain?

Robinhood Chain is an Ethereum-compatible Layer 2 built with Arbitrum Nitro. It is designed for tokenized real-world assets and other onchain financial applications while retaining the standard EVM development model.

### Ethereum-Compatible Development

- **Standard EVM tooling** - Use ethers, viem, web3.js, Hardhat, Foundry, and Solidity without a chain-specific SDK.
- **ETH-denominated fees** - ETH is the native currency for execution and L1 data costs.
- **Arbitrum Nitro** - Applications use familiar Ethereum JSON-RPC methods and Nitro's execution model.

### Fast Application Feedback

- **Sub-second soft confirmations** - The sequencer gives applications a fast view of accepted transactions.
- **WebSocket subscriptions** - Stream new heads and logs instead of polling the HTTPS endpoint.
- **Ethereum settlement** - L2 activity is ultimately settled through the underlying Arbitrum rollup on Ethereum.

### Archive and Debug Access

- **Historical state** - Query balances, contract state, calls, and logs at earlier block heights.
- **Execution traces** - Use Nitro's `debug_*` methods to inspect transaction and block execution.
- **Production routing** - Use the same authenticated Dwellir endpoint format as other supported EVM networks.

## Sequencer feed

Stream ordered Nitro messages through Dwellir's [Robinhood sequencer feed](https://www.dwellir.com/docs/robinhood/sequencer-feed). The WebSocket endpoint has a three-day trial and an optional $100 monthly add-on, plus usage.

The feed starts sending messages when you connect. Use a raw WebSocket client and a Nitro payload decoder.

## Quick Start with Robinhood Chain

Connect to Robinhood Chain mainnet through Dwellir's archive-enabled HTTPS and WebSocket endpoints:

### Installation and Setup

Ethers.js
viem
WebSocket

```javascript
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider(
  'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

const network = await provider.getNetwork();
console.log(network.chainId === 4663n);

const blockNumber = await provider.getBlockNumber();
console.log('Latest block:', blockNumber);
```

```typescript
import { createPublicClient, defineChain, http } from 'viem';

const robinhood = defineChain({
  id: 4663,
  name: 'Robinhood Chain',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: {
    default: {
      http: ['https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'],
    },
  },
});

const client = createPublicClient({
  chain: robinhood,
  transport: http(),
});

const blockNumber = await client.getBlockNumber();
```

```javascript
import { ethers } from 'ethers';

const provider = new ethers.WebSocketProvider(
  'wss://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

provider.on('block', (blockNumber) => {
  console.log('New Robinhood Chain block:', blockNumber);
});
```

## Network Specifications

| Parameter        | Value                                                                | Details                                     |
| ---------------- | -------------------------------------------------------------------- | ------------------------------------------- |
| Chain ID         | 4663                                                                 | Mainnet, hexadecimal `0x1237`               |
| Native currency  | ETH                                                                  | Gas and transaction fees                    |
| Execution stack  | Arbitrum Nitro                                                       | EVM-compatible optimistic rollup            |
| Settlement layer | Ethereum                                                             | L1 data availability and settlement         |
| RPC standard     | Ethereum                                                             | JSON-RPC 2.0 over HTTPS and WSS             |
| State access     | Archive                                                              | Historical state queries are supported      |
| Trace support    | `debug_*`                                                            | Parity-style `trace_*` is not enabled       |
| Explorer         | [Robinhood Chain Blockscout](https://robinhoodchain.blockscout.com/) | Mainnet blocks, transactions, and contracts |

## API Reference

The reference covers the Ethereum JSON-RPC and Nitro debug methods enabled on Dwellir's Robinhood Chain deployment. Parity-style `trace_*` methods are not enabled; use the corresponding `debug_trace*` methods for execution analysis.

## RPC Capabilities and Limitations

| Capability                     | Support                | Operational note                                                              |
| ------------------------------ | ---------------------- | ----------------------------------------------------------------------------- |
| HTTPS JSON-RPC                 | Supported              | Use for reads, writes, archive queries, and debug calls                       |
| WebSocket JSON-RPC             | Supported              | Use for `eth_subscribe` and persistent stateful workflows                     |
| Historical state               | Archive                | Fixed block parameters are available for state reads                          |
| `debug_*` namespace            | Supported              | Transaction and block tracing methods are enabled                             |
| `trace_*` namespace            | Not enabled            | Use the corresponding `debug_trace*` method                                   |
| Stateful filters               | Supported              | Filter IDs are backend-local and require connection affinity                  |
| `txpool_*` namespace           | Not exposed            | Do not depend on node-local mempool inspection                                |
| Pending transaction monitoring | No public pending feed | Accepted filter or subscription IDs do not imply pending transaction delivery |

## Common Integration Patterns

### Verify the Network Before Sending Transactions

Check the chain ID when your application starts so a misconfigured provider cannot sign or submit transactions to the wrong network:

```typescript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

const network = await provider.getNetwork();
if (network.chainId !== 4663n) {
  throw new Error(`Expected Robinhood Chain (4663), received ${network.chainId}`);
}
```

### Query Historical State

The archive endpoint accepts fixed block numbers for state reads. This is useful for accounting, indexers, audits, and point-in-time portfolio views:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);
const address = '0x0000000000000000000000000000000000000000';
const historicalBlock = 1_000_000;

const [balance, code] = await Promise.all([
  provider.getBalance(address, historicalBlock),
  provider.getCode(address, historicalBlock),
]);

console.log({ balance, code });
```

For large log ranges, split `eth_getLogs` queries into bounded block windows and checkpoint the last completed block. This keeps retries small and makes an indexer resumable.

### Trace Transaction Execution

Use the `debug` namespace when you need internal call frames or execution diagnostics:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

async function traceTransaction(transactionHash) {
  return provider.send('debug_traceTransaction', [
    transactionHash,
    {
      tracer: 'callTracer',
      tracerConfig: { onlyTopCall: false },
    },
  ]);
}

const trace = await traceTransaction('0xTRANSACTION_HASH');
console.log(trace);
```

`debug_traceBlockByNumber` and `debug_traceBlockByHash` are available for block-level analysis. Trace requests can be computationally expensive, so cache immutable results and avoid tracing the same finalized transaction repeatedly.

### Subscribe to New Blocks over WebSocket

Use one long-lived WSS connection for real-time events. The subscription remains attached to that connection until it is closed or explicitly unsubscribed:

```javascript
import WebSocket from 'ws';

const ws = new WebSocket(
  'wss://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'
);

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'eth_subscribe',
    params: ['newHeads'],
  }));
});

ws.on('message', (data) => {
  const message = JSON.parse(data.toString());
  if (message.method === 'eth_subscription') {
    console.log(message.params.result);
  }
});
```

### Pending transactions and the sequencer feed

Robinhood Chain uses Arbitrum Nitro. Dwellir's follower nodes do not expose the sequencer's private transaction queue before ordering.

`eth_newPendingTransactionFilter` can return a filter ID, and `eth_subscribe("newPendingTransactions")` can return a subscription ID. Neither provides a public pending transaction feed on this endpoint. Empty results do not mean the chain has stopped processing transactions.

For block and event updates, use `eth_subscribe("newHeads")` or `eth_subscribe("logs")`. These report activity after sequencing and execution, before Ethereum settlement.

Robinhood publishes a public Nitro sequencer feed at `wss://feed.mainnet.chain.robinhood.com`. It streams ordered messages, rather than exposing the private queue before ordering. This is Robinhood's upstream service. It uses the Nitro feed protocol, not JSON-RPC `eth_subscribe`.

For authenticated access through Dwellir, see the [sequencer feed guide](https://www.dwellir.com/docs/robinhood/sequencer-feed). It covers access, usage billing, and a Node.js consumer example.

See Robinhood's [public endpoint list](https://docs.robinhood.com/chain/connecting/#public-endpoints) and [full-node guide](https://docs.robinhood.com/chain/run-a-full-node/). The [Nitro whitepaper](https://docs.arbitrum.io/nitro-whitepaper.pdf) describes the feed's ordering guarantees.

### Keep stateful filters on one backend

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection.

For HTTP, preserve the `DWSESSION` cookie between requests. HTTP connection reuse alone does not keep requests on one backend. If the backend changes or a filter expires, recreate the filter. Backfill missed logs with `eth_getLogs` from the last processed block.

## Gas and Finality

Robinhood Chain fees contain an L2 execution component and an L1 data component for publishing transaction data to Ethereum. Both are paid in ETH.

Robinhood Chain uses first-come, first-served transaction ordering. `eth_maxPriorityFeePerGas` currently returns zero; raising the priority tip does not buy earlier ordering. Gas tracker execution-cost estimates do not include the variable Nitro L1 data fee.

### Confirmation Stages

| Stage                  | Meaning                                                        | Application guidance                                                     |
| ---------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------ |
| Sequencer confirmation | The sequencer has accepted and ordered the transaction         | Suitable for responsive UI updates, but still a soft L2 confirmation     |
| L2 block inclusion     | The transaction has a receipt in a Robinhood Chain block       | Persist the block number and hash so reorg handling is deterministic     |
| Ethereum settlement    | The rollup data and state commitment progress through Ethereum | Use this stage when the workflow requires stronger settlement assurance  |
| L2-to-L1 withdrawal    | Assets move through the canonical Arbitrum bridge              | Account for the rollup challenge period before funds are available on L1 |

### Transaction Submission Checklist

1. Verify the connected chain ID is `4663` (`0x1237`).
2. Estimate execution gas immediately before signing.
3. Leave enough ETH for both L2 execution and the variable L1 data component.
4. Submit the signed transaction with `eth_sendRawTransaction`.
5. Treat the sequencer receipt as a soft confirmation and apply the finality threshold appropriate for your application.

## Troubleshooting

### `method not found` for `trace_*`

Robinhood Chain exposes Nitro's `debug_*` namespace, not the Parity-style `trace_*` namespace. Use `debug_traceTransaction`, `debug_traceBlockByNumber`, or `debug_traceBlockByHash`.

### `filter not found` after reconnecting

The filter was created on a previous backend connection. Create a new filter and resume from the last block your application persisted. Use a WebSocket subscription when continuous real-time delivery is a better fit.

### Chain ID mismatch

Confirm the provider URL points to Robinhood Chain and that `eth_chainId` returns `0x1237`. Do not submit a transaction until the configured chain and wallet network both report Chain ID 4663.

## Official Resources

- [Robinhood Chain documentation](https://docs.robinhood.com/chain/)
- [Connect to Robinhood Chain](https://docs.robinhood.com/chain/connecting/)
- [Gas and fees](https://docs.robinhood.com/chain/gas-and-fees/)
- [Transaction finality](https://docs.robinhood.com/chain/transaction-finality/)
- [Robinhood Chain explorer](https://robinhoodchain.blockscout.com/)
- [Arbitrum bridge for Robinhood Chain](https://portal.arbitrum.io/bridge?destinationChain=robinhood-chain\&sourceChain=ethereum)
- [Robinhood Chain status](https://status.robinhoodchain.offchain.io/)

---

## debug_traceBlock - Robinhood RPC Method

# debug_traceBlock - Robinhood RPC Method

Traces all transactions in a block on Robinhood Chain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Robinhood Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for Robinhood Chain developers, financial application teams, and EVM builders:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Robinhood
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90323f90221a0339483274170c038b4abee001fceb609cb30c5f39eb83ba164b7f198ac339252a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794a4b000000000000000000073657175656e636572a0734991ab48dcdaf5072b8f9670b6f0b2949975acb714fa5d8793196d98005b96a090b894a71eaa3088d08e6c52044d141ad1124c437582556d5ae9ba6d0810d9dda03d6a53a4d2031c6a2f98e048e60c13834b59b825a283a010f5102b49b6f547a9b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018201188704000000000000829ffc846a0141c7a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000017e858c000000000000003300000000000000008800000000000000338405f5e100f8fcb88c6af889821237b8846bf6a42d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017e858c00000000000000000000000000000000000000000000000000000000000001180000000000000000000000000000000000000000000000000000000000000051f86c2c841dcd650082bea294d38743b48d26743c0ec6898d699394fbc94657ee87071afd498d000080822492a041a6eb01e893ba77a66bf4b49905df128412551cfd7eeb894709eaef74879c42a049f578a6810063e5a9c638590950ee76da2a8dfc64a123cb089b1b6eab325949c0",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Robinhood:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Robinhood blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/robinhood/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/robinhood/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Robinhood RPC Method

# debug_traceBlockByHash - Robinhood RPC Method

Traces all transactions in a block on Robinhood Chain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Robinhood Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Robinhood
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Robinhood:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Robinhood:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/robinhood/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/robinhood/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/robinhood/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/robinhood/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Robinhood RPC Method

# debug_traceBlockByNumber - Robinhood RPC Method

Traces all transactions in a block on Robinhood Chain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Robinhood Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Robinhood execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Robinhood:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Robinhood:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/robinhood/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/robinhood/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/robinhood/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Robinhood RPC Method

# debug_traceCall - Robinhood RPC Method

Traces a call on Robinhood Chain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Robinhood Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for Robinhood Chain developers, financial application teams, and EVM builders:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Robinhood
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "data": "0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
        "data": "0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
        "data": "0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    data: '0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    data: '0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    'data': '0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
        "data": "0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Robinhood to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Robinhood:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Robinhood:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/robinhood/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/robinhood/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/robinhood/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Robinhood RPC Method

# debug_traceTransaction - Robinhood RPC Method

Traces a transaction execution on Robinhood Chain by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Robinhood
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/robinhood/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/robinhood/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Robinhood RPC Method

# eth_accounts - Robinhood RPC Method

Returns a list of addresses owned by the client on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for Robinhood Chain developers, financial application teams, and EVM builders in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/robinhood/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/robinhood/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Robinhood RPC Method

# eth_blockNumber - Robinhood RPC Method

Returns the number of the most recent block on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_blockNumber` is fundamental for Robinhood Chain developers, financial application teams, and EVM builders:

- **Syncing Applications** - Keep your dApp in sync with the latest Robinhood blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Robinhood block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Robinhood block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Robinhood block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Robinhood block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Robinhood block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Robinhood:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Robinhood:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Robinhood node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/robinhood/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/robinhood/eth_syncing) - Check if node is still syncing

---

## eth_call - Robinhood RPC Method

# eth_call - Robinhood RPC Method

Executes a new message call immediately without creating a transaction on Robinhood Chain. Used for reading smart contract state.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

The `eth_call` method serves these key scenarios for Robinhood Chain developers, financial application teams, and EVM builders:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Robinhood
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';
const walletAddress = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Robinhood. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Robinhood
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Robinhood Chain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "data": "0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "data": "0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    data := common.FromHex("0x70a082310000000000000000000000000Bd7D308f8E1639FAb988df18A8011f41EAcAD73")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/robinhood/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/robinhood/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Robinhood RPC Method

# eth_chainId - Robinhood RPC Method

Returns the chain ID used for transaction signing on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_chainId` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/robinhood/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/robinhood/eth_syncing) - Check sync status

---

## eth_estimateGas - Robinhood RPC Method

# eth_estimateGas - Robinhood RPC Method

Estimates the gas necessary to execute a transaction on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for Robinhood Chain developers, financial application teams, and EVM builders:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Robinhood
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Robinhood.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Robinhood may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "to": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/robinhood/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/robinhood/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Robinhood RPC Method

# eth_feeHistory - Robinhood RPC Method

Returns historical gas fee data on Robinhood Chain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for Robinhood Chain developers, financial application teams, and EVM builders:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Robinhood without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Robinhood.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Robinhood) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/robinhood/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/robinhood/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/robinhood/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Robinhood RPC Method

# eth_gasPrice - Robinhood RPC Method

Returns the current gas price on Robinhood Chain in wei.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for Robinhood Chain developers, financial application teams, and EVM builders:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Robinhood
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Robinhood. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Robinhood, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Robinhood: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Robinhood supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/robinhood/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/robinhood/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/robinhood/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Robinhood RPC Method

# eth_getBalance - Robinhood RPC Method

Returns the balance of a given address on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getBalance` is fundamental for Robinhood Chain developers, financial application teams, and EVM builders:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Robinhood
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Robinhood Chain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Robinhood Chain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Robinhood`);
  return balance;
}

displayBalance('0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Robinhood at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Robinhood')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Robinhood')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Robinhood Chain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/robinhood/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/robinhood/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Robinhood RPC Method

# eth_getBlockByHash - Robinhood RPC Method

Returns information about a block by hash on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getBlockByHash` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Robinhood Chain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Robinhood Chain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Robinhood Chain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/robinhood/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Robinhood RPC Method

# eth_getBlockByNumber - Robinhood RPC Method

Returns information about a block by block number on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getBlockByNumber` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Robinhood Chain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Robinhood Chain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Robinhood Chain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/robinhood/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/robinhood/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/robinhood/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Robinhood RPC Method

# eth_getBlockReceipts - Robinhood RPC Method

Returns all transaction receipts for a block on Robinhood Chain. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getBlockReceipts` is useful for Robinhood Chain developers, financial application teams, and EVM builders:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Robinhood Chain, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Robinhood Chain. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xcfbf687d1249a855e6c335dfdabf08c639cd1da6fd1a8974483d2c0e6736fa61",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/robinhood/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/robinhood/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Robinhood RPC Method

# eth_getCode - Robinhood RPC Method

Returns the bytecode at a given address on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getCode` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Robinhood
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Robinhood:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Robinhood:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/robinhood/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/robinhood/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Robinhood RPC Method

# eth_getFilterChanges - Robinhood RPC Method

Polls a filter on Robinhood Chain for changes since the last poll. Log filters return log objects. Block filters return block hashes.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getFilterChanges` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Robinhood
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block tracking** - Detect new blocks with a block filter

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Robinhood backend affinity

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection.

For HTTP, preserve the `DWSESSION` cookie between requests. HTTP connection reuse alone does not keep requests on one backend. A backend change or filter expiry can cause `filter not found`. Recreate the filter and backfill missed events with `eth_getLogs`.

Robinhood does not expose a public pending transaction pool through these filters. `eth_newPendingTransactionFilter` can return an ID, but polling it does not provide pending hashes. The `newPendingTransactions` subscription also does not provide a pending feed. Use `newHeads` or `logs` subscriptions for block and event updates. See [pending transactions and the sequencer feed](https://www.dwellir.com/docs/robinhood#pending-transactions-and-the-sequencer-feed).

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter or eth_newBlockFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Robinhood:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/robinhood/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/robinhood/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/robinhood/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/robinhood/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/robinhood/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Robinhood RPC Method

# eth_getFilterLogs - Robinhood RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Robinhood Chain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getFilterLogs` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Robinhood
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Robinhood backend affinity

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection.

For HTTP, preserve the `DWSESSION` cookie between requests. HTTP connection reuse alone does not keep requests on one backend. A backend change or filter expiry can cause `filter not found`. Recreate the filter and backfill missed events with `eth_getLogs`.

Robinhood does not expose a public pending transaction pool through these filters. `eth_newPendingTransactionFilter` can return an ID, but polling it does not provide pending hashes. The `newPendingTransactions` subscription also does not provide a pending feed. Use `newHeads` or `logs` subscriptions for block and event updates. See [pending transactions and the sequencer feed](https://www.dwellir.com/docs/robinhood#pending-transactions-and-the-sequencer-feed).

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/robinhood/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/robinhood/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/robinhood/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/robinhood/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Robinhood RPC Method

# eth_getLogs - Robinhood RPC Method

Returns an array of all logs matching a given filter object on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for Robinhood Chain developers, financial application teams, and EVM builders:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Robinhood for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Robinhood Chain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Robinhood.

```javascript
const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Robinhood enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Robinhood Chain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/robinhood/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/robinhood/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Robinhood RPC Method

# eth_getStorageAt - Robinhood RPC Method

Returns the value from a storage position at a given address on Robinhood Chain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getStorageAt` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **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 tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **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": [
    "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "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-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', '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-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';

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-robinhood-mainnet-archive.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 = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
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-robinhood-mainnet-archive.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-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    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 Robinhood:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.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-robinhood-mainnet-archive.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 = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';
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 Robinhood:`);
  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/robinhood/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/robinhood/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/robinhood/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Robinhood RPC Method

# eth_getTransactionByHash - Robinhood RPC Method

Returns the information about a transaction by transaction hash on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getTransactionByHash` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Robinhood Chain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Robinhood Chain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Robinhood Chain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/robinhood/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/robinhood/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Robinhood RPC Method

# eth_getTransactionCount - Robinhood RPC Method

Returns the number of transactions sent from an address on Robinhood Chain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getTransactionCount` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Robinhood
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Robinhood nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73'
nonce = get_transaction_count(address)
print(f'Robinhood nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Robinhood nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Robinhood:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/robinhood/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/robinhood/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/robinhood/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/robinhood/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Robinhood RPC Method

# eth_getTransactionReceipt - Robinhood RPC Method

Returns the receipt of a transaction by transaction hash on Robinhood Chain. Receipt is only available for mined transactions.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_getTransactionReceipt` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Robinhood Chain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Robinhood Chain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Robinhood Chain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x4e9f74aa8f9cdcbc8e694209cef9bc5400019cd4e9011fca5954efb4370dc067")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/robinhood/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/robinhood/eth_getLogs) - Query logs by filter

---

## eth_maxPriorityFeePerGas - Robinhood RPC Method

# eth_maxPriorityFeePerGas - Robinhood RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Robinhood Chain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Robinhood
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Robinhood priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Robinhood priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Robinhood priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Robinhood:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Robinhood:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/robinhood/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/robinhood/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/robinhood/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/robinhood/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_newBlockFilter - Robinhood RPC Method

# eth_newBlockFilter - Robinhood RPC Method

Creates a filter on Robinhood Chain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_newBlockFilter` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Block Monitoring** - Detect new blocks on Robinhood as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Robinhood backend affinity

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection.

For HTTP, preserve the `DWSESSION` cookie between requests. HTTP connection reuse alone does not keep requests on one backend. A backend change or filter expiry can cause `filter not found`. Recreate the filter and backfill missed events with `eth_getLogs`.

Robinhood does not expose a public pending transaction pool through these filters. `eth_newPendingTransactionFilter` can return an ID, but polling it does not provide pending hashes. The `newPendingTransactions` subscription also does not provide a pending feed. Use `newHeads` or `logs` subscriptions for block and event updates. See [pending transactions and the sequencer feed](https://www.dwellir.com/docs/robinhood#pending-transactions-and-the-sequencer-feed).

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Robinhood:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/robinhood/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/robinhood/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/robinhood/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/robinhood/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Robinhood RPC Method

# eth_newFilter - Robinhood RPC Method

Creates a filter object on Robinhood Chain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_newFilter` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Event Monitoring** - Subscribe to specific contract events on Robinhood such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Robinhood backend affinity

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection.

For HTTP, preserve the `DWSESSION` cookie between requests. HTTP connection reuse alone does not keep requests on one backend. A backend change or filter expiry can cause `filter not found`. Recreate the filter and backfill missed events with `eth_getLogs`.

Robinhood does not expose a public pending transaction pool through these filters. `eth_newPendingTransactionFilter` can return an ID, but polling it does not provide pending hashes. The `newPendingTransactions` subscription also does not provide a pending feed. Use `newHeads` or `logs` subscriptions for block and event updates. See [pending transactions and the sequencer feed](https://www.dwellir.com/docs/robinhood#pending-transactions-and-the-sequencer-feed).

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Robinhood:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/robinhood/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/robinhood/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/robinhood/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/robinhood/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/robinhood/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_sendRawTransaction - Robinhood RPC Method

# eth_sendRawTransaction - Robinhood RPC Method

Submits a pre-signed transaction for broadcast to Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for Robinhood Chain developers, financial application teams, and EVM builders:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Robinhood
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Robinhood mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": [
    "0x02f9040f82123732808405f5e1008308fb6a948e70484544526d0e0ab095165ca57dd77b96206980b903a43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006a54dc0400000000000000000000000000000000000000000000000000000000000000030b009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000f8b0a10e4700000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000275654a894873ce0a4b53824b737166e71f5bed900000000000000000000000000000000000000000000000000f8b0a10e470000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002b0bd7d308f8e1639fab988df18a8011f41eacad73002710aa9d744e653720229b99e16e1c461719f92bc645000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000aa9d744e653720229b99e16e1c461719f92bc64500000000000000000000000000000000000000000000000000f8b0a10e4700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000275654a894873ce0a4b53824b737166e71f5bed9c080a0a38aa9bd404837651204bb32f68ce003b34c4228888d77c48d7d13205cf6d2d2a005ce7b264d19499cd448b875a5f443ee2178e5791c53b0aeb150003f810838ae"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/robinhood/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/robinhood/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/robinhood/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/robinhood/eth_getTransactionReceipt) - Get transaction result

---

## eth_syncing - Robinhood RPC Method

# eth_syncing - Robinhood RPC Method

Returns the sync status of your Robinhood Chain node - either `false` when fully synced, or an object describing the sync progress.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_syncing` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Robinhood node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Robinhood node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Robinhood node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/robinhood/eth_blockNumber) - Get current block height
- `net_peerCount` - Check peer connections
- `net_listening` - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/robinhood/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Robinhood RPC Method

# eth_uninstallFilter - Robinhood RPC Method

Removes a filter on Robinhood Chain that was previously created with `eth_newFilter` or `eth_newBlockFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`eth_uninstallFilter` is important for Robinhood Chain developers, financial application teams, and EVM builders:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Robinhood backend affinity

Filter IDs belong to the backend that created them. Create, poll, and uninstall a filter over one persistent WebSocket connection.

For HTTP, preserve the `DWSESSION` cookie between requests. HTTP connection reuse alone does not keep requests on one backend. A backend change or filter expiry can cause `filter not found`. Recreate the filter and backfill missed events with `eth_getLogs`.

Robinhood does not expose a public pending transaction pool through these filters. `eth_newPendingTransactionFilter` can return an ID, but polling it does not provide pending hashes. The `newPendingTransactions` subscription also does not provide a pending feed. Use `newHeads` or `logs` subscriptions for block and event updates. See [pending transactions and the sequencer feed](https://www.dwellir.com/docs/robinhood#pending-transactions-and-the-sequencer-feed).

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter or eth_newBlockFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/robinhood/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/robinhood/eth_newBlockFilter) - Create a new block filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/robinhood/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/robinhood/eth_getFilterLogs) - Get all logs matching a filter

---

## net_version - Robinhood RPC Method

# net_version - Robinhood RPC Method

Returns the current network ID on Robinhood Chain as a decimal string. The network ID identifies which network the node is connected to.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`net_version` is essential for Robinhood Chain developers, financial application teams, and EVM builders:

- **Endpoint Identification** - Confirm your application is connected to the expected Robinhood network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Robinhood network ID:', networkId);

// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Robinhood network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Robinhood network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/robinhood/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- `net_listening` - Check whether the client reports peer-listening state
- `net_peerCount` - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/robinhood/eth_syncing) - Check node sync progress

---

## rpc_modules - Robinhood RPC Method

# rpc_modules - Robinhood RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Robinhood Chain endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`rpc_modules` is useful for Robinhood Chain developers, financial application teams, and EVM builders:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "arb": "1.0",
    "debug": "1.0",
    "eth": "1.0",
    "net": "1.0",
    "rpc": "1.0",
    "web3": "1.0"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/robinhood/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/robinhood/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## Nitro sequencer feed

# Nitro sequencer feed

Dwellir's Robinhood sequencer feed streams ordered Nitro messages over WebSocket. Use it to build feed consumers and inspect transaction ordering.

```text
wss://api-robinhood-mainnet-sequencer.n.dwellir.com/YOUR_API_KEY
```

The server starts sending data after the connection opens. No subscription request is required.

## Access and pricing

Open [Robinhood in the dashboard](https://dashboard.dwellir.com/chains/robinhood) and select the sequencer endpoint. Start its three-day trial, or select the **Robinhood Mainnet Sequencer Feed** add-on.

| Item                | Terms                                                                           |
| ------------------- | ------------------------------------------------------------------------------- |
| Monthly access      | $100 per month, in addition to your base plan and usage                         |
| Eligible paid plans | Developer, Growth, and Scale                                                    |
| Trial               | Three days without the add-on access fee                                        |
| Usage during trial  | Counts against your plan's response allowance                                   |
| Usage unit          | One response per WebSocket data envelope, including confirmation-only envelopes |

The add-on is optional. Starting a trial does not purchase it or automatically convert the trial into a paid subscription. Select the paid add-on to continue after the trial.

Use an API key from the organization that has feed access. An API key alone does not unlock this restricted endpoint.

An envelope can contain multiple sequenced items. Each envelope counts as one response, regardless of its item count. Repeated data sent after reconnecting also counts toward usage.

## Choose the right connection

| Connection                                                                  | Data                                              | Client                                                 |
| --------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------ |
| Sequencer feed                                                              | Ordered Nitro messages before Ethereum settlement | A WebSocket client and Nitro payload decoder           |
| [Archive RPC](https://www.dwellir.com/docs/robinhood#quick-start-with-robinhood-chain)             | Blocks, receipts, logs, state, and traces         | ethers, viem, or another JSON-RPC client               |
| [RPC subscriptions](https://www.dwellir.com/docs/robinhood#subscribe-to-new-blocks-over-websocket) | New blocks and contract logs                      | `eth_subscribe("newHeads")` or `eth_subscribe("logs")` |

The sequencer feed reports messages after the sequencer orders them. It does not expose the private pending transaction queue or provide Ethereum settlement guarantees.

Do not send `eth_subscribe` requests to the feed URL. Keep your existing archive RPC connection for transaction submission and execution results.

## Connect with Node.js

Install [ws](https://github.com/websockets/ws), then save the example as `feed.mjs`:

```bash
npm install ws
```

```javascript
import WebSocket from 'ws';

const apiKey = process.env.DWELLIR_API_KEY;
if (!apiKey) throw new Error('Set DWELLIR_API_KEY');

const ws = new WebSocket(
  `wss://api-robinhood-mainnet-sequencer.n.dwellir.com/${apiKey}`,
);
let lastSequenceNumber;

ws.on('open', () => console.log('Connected to the Robinhood sequencer feed'));

ws.on('message', (data) => {
  try {
    const envelope = JSON.parse(data.toString());
    for (const item of envelope.messages ?? []) {
      const sequenceNumber = item.sequenceNumber;
      if (!Number.isSafeInteger(sequenceNumber)) {
        throw new Error('Invalid or unsafe sequence number');
      }
      if (lastSequenceNumber !== undefined) {
        if (sequenceNumber <= lastSequenceNumber) continue;
        if (sequenceNumber !== lastSequenceNumber + 1) {
          console.warn('Sequence gap:', lastSequenceNumber, '->', sequenceNumber);
        }
      }

      const payload = item.message.message;
      const bytes = Buffer.from(payload.l2Msg, 'base64');
      console.log({ sequenceNumber, kind: payload.header.kind, payloadBytes: bytes.length });
      lastSequenceNumber = sequenceNumber;
    }

    if (envelope.confirmedSequenceNumberMessage) {
      console.log('Feed confirmation:', envelope.confirmedSequenceNumberMessage);
    }
  } catch (error) {
    console.error('Cannot process feed data:', error.message);
    ws.close(1000, 'Consumer stopped');
  }
});

ws.on('error', (error) => console.error('WebSocket error:', error.message));
ws.on('close', (code) => console.log('Feed closed:', code));
```

Set `DWELLIR_API_KEY` in your environment and run:

```bash
node feed.mjs
```

The example logs each item's sequence number, message kind, and decoded byte length. It skips duplicate sequence numbers within one connection. It logs gaps and continues with later items, without recovering missing data.

It closes the connection if an envelope or item cannot be processed. It does not decode transactions or reconnect automatically.

Confirmation-only envelopes have no `messages` array, so the example handles them separately.

## Read the message payload

A WebSocket envelope contains a `messages` array. Each entry represents one sequenced Nitro item, which can contain several transactions.

The following item comes from a Dwellir Robinhood relay sample saved on September 15, 2026. Its message timestamp is `2026-09-15T10:23:29Z`.

Only `l2Msg` is abbreviated below. All other fields match the captured item. [Download the complete item](https://www.dwellir.com/data/examples/robinhood/sequencer-item-63584698.json) to run the decoding example.

```json
{
  "sequenceNumber": 63584698,
  "message": {
    "message": {
      "header": {
        "kind": 3,
        "sender": "0xa4b000000000000000000073657175656e636572",
        "blockNumber": 25982243,
        "timestamp": 1789467809,
        "requestId": null,
        "baseFeeL1": 0
      },
      "l2Msg": "<omitted: 29,252 base64 characters>"
    },
    "delayedMessagesRead": 281088
  },
  "blockHash": "0xc2f05da0f6adcff40d34c8c7f6c049c6c1cdf916691a748d709be144ab7cba1f",
  "signatureV2": "8SQPCb4wLCtys/WhDskmTB5wMqxJ6e7ExEd8lrWSg2JQPAWrCPtMdX7bTPsPlezNZbBwwOi5M5YpNROJkU2xHQA="
}
```

This is one extracted item, not a complete WebSocket envelope. Its sequence number identifies its position in the feed, not a transaction hash.

### Follow the nested fields

There are two `message` levels inside each item. The outer level adds metadata. The inner level contains the incoming-message header and binary payload.

| Field within an item                 | Meaning in this sample                                                         |
| ------------------------------------ | ------------------------------------------------------------------------------ |
| `sequenceNumber`                     | Feed position `63584698`                                                       |
| `message.delayedMessagesRead`        | Cumulative delayed-inbox messages consumed, here `281088`                      |
| `message.message.header.kind`        | `3` identifies a Nitro L2 message                                              |
| `message.message.header.sender`      | Nitro's sequencer sender address, not the signed transaction's sender          |
| `message.message.header.blockNumber` | L1 block `25982243`, not the Robinhood L2 block number                         |
| `message.message.header.timestamp`   | Unix timestamp in seconds, here `1789467809`                                   |
| `message.message.header.requestId`   | Optional request identifier; `null` in this item                               |
| `message.message.header.baseFeeL1`   | L1 base-fee field; `0` in this item, not the transaction's execution gas price |
| `message.message.l2Msg`              | Base64-encoded bytes containing a Nitro transaction batch                      |
| `blockHash`                          | Block hash carried with the feed item, not a transaction hash                  |
| `signatureV2`                        | Base64-encoded feed signature; 65 bytes in this sample                         |

These fields follow Nitro's [feed item](https://github.com/OffchainLabs/nitro/blob/v3.11.3/broadcaster/message/message.go), [metadata](https://github.com/OffchainLabs/nitro/blob/v3.11.3/arbos/arbostypes/messagewithmeta.go), and [incoming message](https://github.com/OffchainLabs/nitro/blob/v3.11.3/arbos/arbostypes/incomingmessage.go) types.

`signatureV2` covers feed data using Nitro's signature scheme. It is separate from each transaction's signature. The example below decodes transactions but does not verify the feed signature.

A confirmation-only envelope instead contains `confirmedSequenceNumberMessage` with a `sequenceNumber`. It can omit `messages` entirely. A feed confirmation does not establish Ethereum settlement.

### Decode the binary batch

Base64 decoding this item's `l2Msg` produces **21,937 bytes**. Its first bytes are:

```text
03 | 00 00 00 00 00 00 00 6e | 04 | 02 f8 6a 82 12 37 ...
```

| Bytes                     | Interpretation                                                         |
| ------------------------- | ---------------------------------------------------------------------- |
| `03`                      | Nitro L2 batch kind                                                    |
| `00 00 00 00 00 00 00 6e` | Eight-byte big-endian length of the first child, `110` bytes           |
| `04`                      | Nitro signed-transaction kind inside that child                        |
| `02 f8 6a ...`            | The remaining `109` bytes encode an Ethereum type-2 signed transaction |

The outer header's `kind: 3` and the payload's `0x03` belong to different type definitions. Inspect both when decoding.

This batch contains **9 signed transactions**. Each child has its own length prefix and kind byte. Nitro also supports other message kinds and nested batches. See its [L2 parser](https://github.com/OffchainLabs/nitro/blob/v3.11.3/arbos/parse_l2.go).

Save the downloaded item as `sequencer-item-63584698.json`. Save this script as `inspect-feed.mjs`, then run `node inspect-feed.mjs`:

```javascript
import { readFileSync } from 'node:fs';

const item = JSON.parse(readFileSync('sequencer-item-63584698.json', 'utf8'));
const payload = Buffer.from(item.message.message.l2Msg, 'base64');
if (item.message.message.header.kind !== 3 || payload[0] !== 3) {
  throw new Error('This example expects a Nitro L2 batch');
}

const transactions = [];
let offset = 1;
while (offset < payload.length) {
  if (offset + 8 > payload.length) throw new Error('Truncated length prefix');
  const length = payload.readBigUInt64BE(offset);
  offset += 8;
  if (length < 2n || length > BigInt(payload.length - offset)) {
    throw new Error('Invalid child length');
  }
  const child = payload.subarray(offset, offset + Number(length));
  if (child[0] !== 4) throw new Error('This example only handles signed-transaction children');
  transactions.push(`0x${child.subarray(1).toString('hex')}`);
  offset += Number(length);
}

console.log({
  payloadBytes: payload.length,
  transactionCount: transactions.length,
  firstSignedTransaction: transactions[0],
});
```

The script reads every child and removes its Nitro kind byte. It rejects other child kinds instead of treating them as signed transactions.

### Decode the first transaction

Install ethers v6 with `npm install ethers@6`. Append the following code to `inspect-feed.mjs` and run it again:

```javascript
import { Transaction } from 'ethers';

const tx = Transaction.from(transactions[0]);
console.log({
  hash: tx.hash,
  type: tx.type,
  chainId: tx.chainId.toString(),
  nonce: tx.nonce,
  from: tx.from,
  to: tx.to,
  valueWei: tx.value.toString(),
  gasLimit: tx.gasLimit.toString(),
  maxFeePerGasWei: tx.maxFeePerGas.toString(),
  maxPriorityFeePerGasWei: tx.maxPriorityFeePerGas.toString(),
  data: tx.data,
});
```

The first transaction in the captured item decodes to:

```json
{
  "hash": "0xbdffb350d63b66fd527ae31dde15dd0567fd74b65f9c6b08c9543c9c1103a8c8",
  "type": 2,
  "chainId": "4663",
  "nonce": 278,
  "from": "0x606e7523F19f37C0F1cEaD4C0A86E661Ee264b87",
  "to": "0x606e7523F19f37C0F1cEaD4C0A86E661Ee264b87",
  "valueWei": "0",
  "gasLimit": "21000",
  "maxFeePerGasWei": "1000000000",
  "maxPriorityFeePerGasWei": "1",
  "data": "0x"
}
```

It is a zero-value transaction to the sender's own address, with no call data. Chain ID `4663` identifies Robinhood mainnet.

The fee fields are signed transaction limits, not the fee paid. Use its hash with [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/robinhood/eth_getTransactionReceipt) to inspect execution results.

The archive receipt for this transaction reports success in Robinhood L2 block `63584698`. Its block hash matches this feed item's `blockHash`.

For a consumer that handles every Nitro message kind, follow [Arbitrum's feed format guide](https://docs.arbitrum.io/run-arbitrum-node/sequencer/read-sequencer-feed) and the versioned Nitro parser.

## Handle interruptions

For a persistent consumer, reconnect with backoff after a disconnect. Save the last processed sequence number after your application commits each item.

Deduplicate repeated sequence numbers across connections. Detect gaps before advancing your saved position. The example only logs gaps; applications that require complete data must recover them.

Do not assume the feed can replay arbitrary history or resume from a requested sequence number. Recover block and log history through the [archive RPC endpoint](https://www.dwellir.com/docs/robinhood), where it meets your data needs.

If the WebSocket handshake returns `403`, check the API key's organization and its trial or paid add-on access. If the connection closes, check access and usage limits before reconnecting.

Robinhood also operates its own [public upstream feed](https://docs.robinhood.com/chain/connecting/#public-endpoints). Dwellir's endpoint adds authenticated access through your Dwellir organization.

---

## web3_clientVersion - Robinhood RPC Method

# web3_clientVersion - Robinhood RPC Method

Returns the current client software version string for your Robinhood Chain node, including the client name, version number, OS, and runtime.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

## When to Use This Method

`web3_clientVersion` is valuable for Robinhood Chain developers, financial application teams, and EVM builders:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Robinhood client:', clientVersion);

// Using fetch
const response = await fetch('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Robinhood client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Robinhood client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/robinhood/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/robinhood/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/robinhood/web3_sha3) - Compute Keccak-256 hash via RPC
- `net_peerCount` - Get number of connected peers

---

## web3_sha3 - Robinhood RPC Method

# web3_sha3 - Robinhood RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Robinhood Chain.

> **Why Robinhood?** Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for Robinhood Chain developers, financial application teams, and EVM builders:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-robinhood-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/robinhood/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/robinhood/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/robinhood/web3_clientVersion) - Get node client version

---

## Ronin - Gaming-Focused Blockchain Documentation

# Ronin - Gaming-Focused Blockchain Documentation

## Ronin RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Ronin supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Ronin?

Ronin is an EVM-compatible blockchain built for gaming, powering player-owned economies. Originally developed by Sky Mavis for Axie Infinity, Ronin offers:

### **Gaming-First Design**

- **Sub-3 second block times** - Ultra-fast gaming interactions
- **Optimized for NFTs** - Purpose-built for digital ownership
- **Player-owned economies** - Enable true ownership of game assets

### **Proven Performance**

- **250K+ daily active users** - Battle-tested at scale
- **$4B+ NFT volume processed** - Proven ecosystem
- **2M+ wallet downloads** - Strong adoption

### **Low-Cost Operations**

- **RON gas token** - Minimal transaction fees
- **DPoS consensus** - Energy-efficient validation
- **Minimal block finality** - \~6 seconds for confirmation

## Quick Start with Ronin

Connect to Ronin in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Ronin mainnet
const provider = new JsonRpcProvider(
  'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Ronin mainnet
const web3 = new Web3(
  'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Ronin:', chainId === 2020);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http, defineChain } from 'viem';

// Define Ronin chain
const ronin = defineChain({
  id: 2020,
  name: 'Ronin',
  network: 'ronin',
  nativeCurrency: {
    decimals: 18,
    name: 'RON',
    symbol: 'RON',
  },
  rpcUrls: {
    default: {
      http: ['https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
});

// Create Ronin client
const client = createPublicClient({
  chain: ronin,
  transport: http('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x0b7007c13325c48911f73a2dad5fa5dcbf808adc',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter  | Value     | Details       |
| ---------- | --------- | ------------- |
| Chain ID   | 2020      | Mainnet       |
| Block Time | 3 seconds | Minimum       |
| Gas Token  | RON       | Native token  |
| Consensus  | DPoS      | 22 validators |

## API Reference

Ronin supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with gaming-optimized performance.

## Common Integration Patterns

### Gaming Asset Management

Efficiently manage NFTs and gaming tokens:

```javascript
// Check NFT ownership
async function checkNFTOwnership(contractAddress, tokenId, userAddress) {
  const contract = new ethers.Contract(contractAddress, erc721Abi, provider);
  const owner = await contract.ownerOf(tokenId);
  return owner.toLowerCase() === userAddress.toLowerCase();
}

// Batch token balance queries
async function getUserTokens(userAddress, tokenAddresses) {
  const calls = tokenAddresses.map(address => ({
    method: 'eth_call',
    params: [{
      to: address,
      data: '0x70a08231' + userAddress.slice(2).padStart(64, '0') // balanceOf(address)
    }, 'latest']
  }));

  return await provider.send(calls);
}
```

### High-Frequency Game Actions

Optimize for rapid game state updates:

```javascript
// Fast transaction confirmation
async function waitForGameAction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Ronin's fast finality means 1 confirmation is usually enough
  console.log('Game action confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Gas estimation for game transactions
async function estimateGameTxCost(gameAction) {
  const gasEstimate = await provider.estimateGas(gameAction);
  const gasPrice = await provider.getGasPrice();

  // Calculate cost in RON
  const cost = gasEstimate * gasPrice;
  return ethers.formatEther(cost);
}
```

### Event Monitoring for Games

Track game events efficiently:

```javascript
// Monitor game events with optimized batching
async function trackGameEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 5000; // Ronin handles larger batches well

  const currentBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Gaming-Optimized Batching**

Leverage Ronin's gaming focus for efficient operations:

```javascript
const gamingBatch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [playerAddress, 'latest'] },
  { method: 'eth_call', params: [{ to: gameContract, data: gameStateCall }, 'latest'] }
];

const results = await provider.send(gamingBatch);
```

### 2. **Connection Pooling for Games**

Maintain persistent connections for real-time gaming:

```javascript
// Gaming-optimized provider singleton
class RoninGameProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        {
          staticNetwork: ethers.Network.from({
            name: 'ronin',
            chainId: 2020
          })
        }
      );
    }
    return this.instance;
  }
}
```

### 3. **Game State Caching**

Cache game state for improved UX:

```javascript
const gameStateCache = new Map();

async function getCachedGameState(gameId) {
  const key = `game_${gameId}`;

  if (!gameStateCache.has(key)) {
    const state = await contract.getGameState(gameId);
    gameStateCache.set(key, state);

    // Clear cache after 30 seconds (game state can change)
    setTimeout(() => gameStateCache.delete(key), 30000);
  }

  return gameStateCache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient RON for transaction"

Ronin uses RON tokens for gas fees:

```javascript
// Check RON balance before transactions
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + (tx.value || 0n);

if (balance < totalRequired) {
  throw new Error(`Need ${ethers.formatEther(totalRequired - balance)} more RON`);
}
```

### Error: "Transaction underpriced"

Ensure competitive gas pricing:

```javascript
// Get current network fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  gasPrice: feeData.gasPrice, // Ronin uses legacy gas pricing
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement backoff for high-frequency gaming:

```javascript
async function gameActionWithRetry(fn, maxRetries = 5) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        // Shorter backoff for gaming scenarios
        await new Promise(r => setTimeout(r, 500 * (2 ** i)));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet to Ronin

Migrating your gaming dApp to Ronin:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Ronin)
const provider = new JsonRpcProvider(
  'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Same smart contract interface
// Same Web3 libraries work
// Note: Different chain ID (2020)
// Note: RON instead of ETH for gas
// Note: Different block explorer
```

## Smoke Tests

Verify your Ronin integration with these tests:

```javascript
// Test 1: Network connection
const chainId = await provider.send('eth_chainId', []);
console.log('Connected to Ronin:', parseInt(chainId) === 2020);

// Test 2: Recent block data
const latestBlock = await provider.send('eth_getBlockByNumber', ['latest', false]);
console.log('Latest block:', parseInt(latestBlock.number));

// Test 3: Token balance check (USDC on Ronin)
const usdcBalance = await provider.send('eth_call', [{
  to: '0x0b7007c13325c48911f73a2dad5fa5dcbf808adc',
  data: '0x70a08231000000000000000000000000' + 'YOUR_ADDRESS'.slice(2)
}, 'latest']);
console.log('USDC balance check successful');
```

## Resources & Tools

### Official Resources

- [Ronin Documentation](https://docs.roninchain.com)
- [Ronin Explorer](https://app.roninchain.com)
- [Ronin Bridge](https://app.roninchain.com/bridge)

### Developer Tools

- [Ronin Testnet Faucet](https://faucet.roninchain.com/)
- [Hardhat Ronin Config](https://docs.roninchain.com/developers/smart-contracts/deploy)
- [Remix IDE Support](https://remix.ethereum.org/)

### Gaming Ecosystem

- [Axie Infinity](https://axieinfinity.com/)
- [Pixels](https://pixels.xyz/)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building gaming experiences on Ronin with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Ronin RPC Method

# debug_traceBlock - Ronin RPC Method

Traces all transactions in a block on Ronin by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ronin - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Ronin
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Ronin:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Ronin blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ronin/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ronin/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ronin/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ronin/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Ronin RPC Method

# debug_traceBlockByHash - Ronin RPC Method

Traces all transactions in a block on Ronin identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ronin - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Ronin
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Ronin:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Ronin:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/ronin/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ronin/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ronin/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ronin/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ronin/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Ronin RPC Method

# debug_traceBlockByNumber - Ronin RPC Method

Traces all transactions in a block on Ronin identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Ronin - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Ronin execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Ronin:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Ronin:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/ronin/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ronin/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ronin/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/ronin/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Ronin RPC Method

# debug_traceCall - Ronin RPC Method

Traces a call on Ronin without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Ronin - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Ronin
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "data": "0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
        "data": "0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
        "data": "0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    data: '0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    data: '0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    'data': '0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
        "data": "0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Ronin to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Ronin:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Ronin:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/ronin/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ronin/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ronin/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/ronin/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Ronin RPC Method

# debug_traceTransaction - Ronin RPC Method

Traces a transaction execution on Ronin by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Ronin
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/ronin/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/ronin/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Ronin RPC Method

# eth_accounts - Ronin RPC Method

Returns a list of addresses owned by the client on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for game developers, NFT gaming studios, and teams building play-to-earn economies in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/ronin/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/ronin/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Ronin RPC Method

# eth_blockNumber - Ronin RPC Method

Returns the number of the most recent block on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_blockNumber` is fundamental for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Syncing Applications** - Keep your dApp in sync with the latest Ronin blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Ronin block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Ronin block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Ronin block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Ronin block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ronin block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Ronin:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Ronin:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Ronin node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ronin/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/ronin/eth_syncing) - Check if node is still syncing

---

## eth_call - Ronin RPC Method

# eth_call - Ronin RPC Method

Executes a new message call immediately without creating a transaction on Ronin. Used for reading smart contract state.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

The `eth_call` method serves these key scenarios for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Ronin
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';
const walletAddress = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Ronin. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Ronin
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Ronin

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "data": "0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "data": "0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    data := common.FromHex("0x70a08231000000000000000000000000e514d9DEB7966c8BE0ca922de8a064264eA6bcd4")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Ronin RPC Method

# eth_chainId - Ronin RPC Method

Returns the chain ID used for transaction signing on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_chainId` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/ronin/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/ronin/eth_syncing) - Check sync status

---

## eth_coinbase - Ronin RPC Method

# eth_coinbase - Ronin RPC Method

Checks the legacy `eth_coinbase` compatibility method on Ronin. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for game developers, NFT gaming studios, and teams building play-to-earn economies when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Ronin coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Ronin coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Ronin coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ronin coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Ronin coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Ronin nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/ronin/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/ronin/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/ronin/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Ronin RPC Method

# eth_estimateGas - Ronin RPC Method

Estimates the gas necessary to execute a transaction on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Ronin
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Ronin.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Ronin may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "to": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ronin/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Ronin RPC Method

# eth_feeHistory - Ronin RPC Method

Returns historical gas fee data on Ronin, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Ronin without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Ronin.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Ronin) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ronin/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/ronin/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Ronin RPC Method

# eth_gasPrice - Ronin RPC Method

Returns the current gas price on Ronin in wei.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Ronin
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Ronin. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Ronin, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Ronin: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Ronin supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/ronin/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/ronin/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Ronin RPC Method

# eth_getBalance - Ronin RPC Method

Returns the balance of a given address on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getBalance` is fundamental for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Ronin
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Ronin
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Ronin. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Ronin`);
  return balance;
}

displayBalance('0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Ronin at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Ronin')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Ronin')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Ronin.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/ronin/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/ronin/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Ronin RPC Method

# eth_getBlockByHash - Ronin RPC Method

Returns information about a block by hash on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getBlockByHash` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Ronin
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Ronin.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Ronin.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/ronin/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Ronin RPC Method

# eth_getBlockByNumber - Ronin RPC Method

Returns information about a block by block number on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getBlockByNumber` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Ronin
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Ronin with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Ronin. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/ronin/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ronin/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ronin/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Ronin RPC Method

# eth_getBlockReceipts - Ronin RPC Method

Returns all transaction receipts for a block on Ronin. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getBlockReceipts` is useful for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Ronin, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Ronin. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x7e20c01a0cee7c8a64e5ba0841a8c59cc82dcb71fa109cbb7f75b44b65dbd3ee",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ronin/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ronin/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Ronin RPC Method

# eth_getCode - Ronin RPC Method

Returns the bytecode at a given address on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getCode` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Ronin
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Ronin:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Ronin:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/ronin/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/ronin/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Ronin RPC Method

# eth_getFilterChanges - Ronin RPC Method

Polls a filter on Ronin for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getFilterChanges` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Ronin
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Ronin:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ronin/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ronin/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ronin/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ronin/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/ronin/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Ronin RPC Method

# eth_getFilterLogs - Ronin RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Ronin. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getFilterLogs` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Ronin
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ronin/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ronin/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/ronin/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ronin/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Ronin RPC Method

# eth_getLogs - Ronin RPC Method

Returns an array of all logs matching a given filter object on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Ronin for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Ronin
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Ronin.

```javascript
const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Ronin enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Ronin, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ronin/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ronin/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Ronin RPC Method

# eth_getStorageAt - Ronin RPC Method

Returns the value from a storage position at a given address on Ronin. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getStorageAt` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **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 blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **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": [
    "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "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-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4', '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-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';

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-ronin-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 = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
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-ronin-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-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    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 Ronin:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-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-ronin-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 = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';
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 Ronin:`);
  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/ronin/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/ronin/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/ronin/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Ronin RPC Method

# eth_getTransactionByHash - Ronin RPC Method

Returns the information about a transaction by transaction hash on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getTransactionByHash` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Ronin
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Ronin. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Ronin. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ronin/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Ronin RPC Method

# eth_getTransactionCount - Ronin RPC Method

Returns the number of transactions sent from an address on Ronin, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getTransactionCount` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Ronin
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Ronin nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4'
nonce = get_transaction_count(address)
print(f'Ronin nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Ronin nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Ronin:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/ronin/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ronin/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ronin/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Ronin RPC Method

# eth_getTransactionReceipt - Ronin RPC Method

Returns the receipt of a transaction by transaction hash on Ronin. Receipt is only available for mined transactions.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_getTransactionReceipt` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Ronin and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Ronin. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Ronin, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x273d9bf15cafb4896d6c1f7131e08986538709abead6316a77cd5f6b363388cb")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ronin/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/ronin/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Ronin RPC Method

# eth_hashrate - Ronin RPC Method

Returns the legacy `eth_hashrate` compatibility value on Ronin. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Ronin hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Ronin hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Ronin hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ronin hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Ronin hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/ronin/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/ronin/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/ronin/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Ronin RPC Method

# eth_maxPriorityFeePerGas - Ronin RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Ronin. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Ronin
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Ronin priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Ronin priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Ronin priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Ronin:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Ronin:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/ronin/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/ronin/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/ronin/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Ronin RPC Method

# eth_mining - Ronin RPC Method

Checks the legacy `eth_mining` compatibility method on Ronin. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Ronin mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Ronin mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Ronin mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Ronin mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Ronin mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/ronin/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/ronin/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/ronin/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Ronin RPC Method

# eth_newBlockFilter - Ronin RPC Method

Creates a filter on Ronin that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_newBlockFilter` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Block Monitoring** - Detect new blocks on Ronin as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Ronin:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ronin/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ronin/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/ronin/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/ronin/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Ronin RPC Method

# eth_newFilter - Ronin RPC Method

Creates a filter object on Ronin based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_newFilter` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Event Monitoring** - Subscribe to specific contract events on Ronin such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Ronin:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ronin/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ronin/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/ronin/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ronin/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ronin/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Ronin RPC Method

# eth_newPendingTransactionFilter - Ronin RPC Method

Creates a filter on Ronin that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Mempool Monitoring** - Observe unconfirmed transactions on Ronin to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for blockchain gaming (Axie Infinity, Pixels), gaming NFT marketplaces, and in-game token economies

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Ronin...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Ronin:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ronin/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/ronin/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/ronin/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Ronin RPC Method

# eth_protocolVersion - Ronin RPC Method

Returns the current Ethereum protocol version used by the Ronin node.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_protocolVersion` is useful for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Ronin protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Ronin protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Ronin protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Ronin protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ronin protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Ronin nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/ronin/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/ronin/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/ronin/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Ronin RPC Method

# eth_sendRawTransaction - Ronin RPC Method

Submits a pre-signed transaction for broadcast to Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Ronin
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Ronin mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/ronin/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/ronin/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/ronin/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Ronin RPC Method

# eth_sendTransaction - Ronin RPC Method

Creates and sends a new transaction from an unlocked account on Ronin. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for game developers, NFT gaming studios, and teams building play-to-earn economies in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Ronin tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Ronin tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Ronin tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Ronin tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ronin tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Ronin dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/ronin/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/ronin/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Ronin RPC Method

# eth_signTransaction - Ronin RPC Method

Signs a transaction with the private key of the specified account on Ronin without submitting it to the network.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for game developers, NFT gaming studios, and teams building play-to-earn economies in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Ronin tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Ronin tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Ronin tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Ronin:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/ronin/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/ronin/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/ronin/eth_accounts) - List accounts available for signing

---

## eth_syncing - Ronin RPC Method

# eth_syncing - Ronin RPC Method

Returns the sync status of your Ronin node - either `false` when fully synced, or an object describing the sync progress.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_syncing` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Ronin node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Ronin node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Ronin node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/ronin/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/ronin/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/ronin/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/ronin/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Ronin RPC Method

# eth_uninstallFilter - Ronin RPC Method

Removes a filter on Ronin that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`eth_uninstallFilter` is important for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/ronin/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/ronin/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/ronin/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/ronin/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/ronin/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Ronin RPC Method

# net_listening - Ronin RPC Method

Checks whether the connected Ronin client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`net_listening` is useful for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Ronin node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Ronin node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Ronin node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/ronin/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/ronin/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ronin/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/ronin/web3_clientVersion) - Get node client info

---

## net_peerCount - Ronin RPC Method

# net_peerCount - Ronin RPC Method

Returns the number of peers currently connected to your Ronin node.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`net_peerCount` is important for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Ronin deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Ronin peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Ronin peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Ronin peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Ronin nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/ronin/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/ronin/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ronin/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/ronin/web3_clientVersion) - Get node client info

---

## net_version - Ronin RPC Method

# net_version - Ronin RPC Method

Returns the current network ID on Ronin as a decimal string. The network ID identifies which network the node is connected to.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`net_version` is essential for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Endpoint Identification** - Confirm your application is connected to the expected Ronin network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Ronin network ID:', networkId);

// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Ronin network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ronin network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/ronin/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/ronin/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/ronin/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/ronin/eth_syncing) - Check node sync progress

---

## rpc_modules - Ronin RPC Method

# rpc_modules - Ronin RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Ronin endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`rpc_modules` is useful for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/ronin/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/ronin/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Ronin RPC Method

# web3_clientVersion - Ronin RPC Method

Returns the current client software version string for your Ronin node, including the client name, version number, OS, and runtime.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

## When to Use This Method

`web3_clientVersion` is valuable for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Ronin client:', clientVersion);

// Using fetch
const response = await fetch('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Ronin client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Ronin client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/ronin/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/ronin/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/ronin/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/ronin/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Ronin RPC Method

# web3_sha3 - Ronin RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Ronin.

> **Why Ronin?** Build on the gaming-first blockchain with 1M+ daily active wallets and $6.47B in NFT trading volume with purpose-built for gaming with $1.3B+ Axie revenue, zkEVM upgrade planned, Katana DEX, and Tama fair launch platform.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for game developers, NFT gaming studios, and teams building play-to-earn economies:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-ronin-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/ronin/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/ronin/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/ronin/web3_clientVersion) - Get node client version

---

## Scroll - zkEVM Layer 2 Documentation

# Scroll - zkEVM Layer 2 Documentation

## Scroll RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Scroll supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Scroll?

Scroll is a zkRollup Layer 2 solution for Ethereum that maintains full EVM compatibility while leveraging zero-knowledge proofs for enhanced security and efficiency. Built by Ethereum developers for the Ethereum community, Scroll offers:

### **Zero-Knowledge Security**

- **zkEVM technology** - Native EVM compatibility with ZK proof verification
- **Ethereum-level security** - Inherits L1 security guarantees through cryptographic proofs
- **Type 3 zkEVM** - Bytecode-compatible with plans to evolve to Type 1

### **Developer-First Experience**

- **Seamless migration** - Existing Ethereum dApps work without code changes
- **Native tooling support** - Hardhat, Remix, MetaMask, and all Ethereum tools
- **100+ ecosystem projects** - Growing DeFi and Web3 application ecosystem

### **Cost-Effective Scaling**

- **Dramatically lower fees** - Orders of magnitude cheaper than Ethereum L1
- **$281M+ TVL** - Strong and growing total value locked
- **119M+ transactions** - Proven at scale with millions of transactions processed

## Quick Start with Scroll

Connect to Scroll in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Scroll mainnet
const provider = new JsonRpcProvider(
  'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Scroll mainnet
const web3 = new Web3(
  'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Scroll:', chainId === 534352);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { scroll } from 'viem/chains';

// Create Scroll client
const client = createPublicClient({
  chain: scroll,
  transport: http('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to Scroll mainnet
w3 = Web3(Web3.HTTPProvider(
  'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection
print('Connected:', w3.is_connected())
print('Chain ID:', w3.eth.chain_id)

# Get latest block number
latest_block = w3.eth.block_number
print(f'Latest block: {latest_block}')
```

## Network Information

| Parameter    | Value    | Details        |
| ------------ | -------- | -------------- |
| Chain ID     | 534352   | Mainnet        |
| Gas Token    | ETH      | Native token   |
| RPC Standard | Ethereum | JSON-RPC 2.0   |
| Consensus    | zkRollup | Zero-Knowledge |

## API Reference

Scroll supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods with zkEVM compatibility.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Check transaction success
  if (receipt.status === 1) {
    console.log('Transaction confirmed:', receipt.transactionHash);
    console.log('Gas used:', receipt.gasUsed.toString());
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Scroll zkEVM:

```javascript
// Get current fee data for EIP-1559 transactions
const feeData = await provider.getFeeData();

// Estimate gas for transaction
const gasLimit = await provider.estimateGas({
  to: recipient,
  value: ethers.parseEther("0.1"),
  data: "0x"
});

// Calculate total transaction cost
const maxFee = feeData.maxFeePerGas * gasLimit;
console.log('Max transaction cost:', ethers.formatEther(maxFee), 'ETH');
```

### Event Filtering

Efficiently query contract events:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Recommended batch size
  const currentBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class ScrollProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Wrong chain ID"

Scroll uses chain ID 534352. Ensure your wallet and application are configured correctly:

```javascript
// Verify chain connection
const network = await provider.getNetwork();
if (network.chainId !== 534352n) {
  throw new Error(`Wrong network! Expected 534352, got ${network.chainId}`);
}
```

### Error: "Transaction underpriced"

Scroll uses EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Smoke Tests

### Basic Connectivity Tests

cURL
Ethers.js
Web3.py

```bash
# Test connection and get latest block
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
  https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY

# Expected response: {"jsonrpc":"2.0","id":1,"result":"0x..."}
```

```javascript
const provider = new JsonRpcProvider(
  'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Test basic connectivity
const blockNumber = await provider.getBlockNumber();
const network = await provider.getNetwork();

console.log('Block number:', blockNumber);
console.log('Chain ID:', network.chainId); // Should be 534352n
console.log('Chain name:', network.name);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider(
  'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Test connection
print('Connected:', w3.is_connected())
print('Chain ID:', w3.eth.chain_id)  # Should be 534352
print('Block number:', w3.eth.block_number)
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to Scroll zkEVM requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Scroll)
const provider = new JsonRpcProvider(
  'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Full EVM compatibility
// Note: Different chain ID (534352)
// Note: Separate block numbers
// Note: Much lower gas costs
```

## Resources & Tools

### Official Resources

- [Scroll Documentation](https://docs.scroll.io)
- [Scroll Bridge](https://scroll.io/bridge)
- [Scroll Block Explorer](https://scrollscan.com)

### Developer Tools

- [GitHub Repository](https://github.com/scroll-tech)
- [Tooling deployed on Scroll](https://docs.scroll.io/en/developers/tooling-deployed-on-scroll)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Scroll zkEVM with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Scroll RPC Method

# debug_traceBlock - Scroll RPC Method

Traces all transactions in a block on Scroll by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Scroll - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Scroll
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Scroll:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Scroll blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/scroll/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/scroll/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/scroll/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/scroll/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Scroll RPC Method

# debug_traceBlockByHash - Scroll RPC Method

Traces all transactions in a block on Scroll identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Scroll - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Scroll
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Scroll:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Scroll:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/scroll/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/scroll/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/scroll/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/scroll/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/scroll/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Scroll RPC Method

# debug_traceBlockByNumber - Scroll RPC Method

Traces all transactions in a block on Scroll identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Scroll - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Scroll execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Scroll:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Scroll:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/scroll/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/scroll/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/scroll/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/scroll/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Scroll RPC Method

# debug_traceCall - Scroll RPC Method

Traces a call on Scroll without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Scroll - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Scroll
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x5300000000000000000000000000000000000004",
      "data": "0x70a082310000000000000000000000005300000000000000000000000000000000000004"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5300000000000000000000000000000000000004",
        "data": "0x70a082310000000000000000000000005300000000000000000000000000000000000004"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5300000000000000000000000000000000000004",
        "data": "0x70a082310000000000000000000000005300000000000000000000000000000000000004"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5300000000000000000000000000000000000004',
    data: '0x70a082310000000000000000000000005300000000000000000000000000000000000004'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5300000000000000000000000000000000000004',
    data: '0x70a082310000000000000000000000005300000000000000000000000000000000000004'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x5300000000000000000000000000000000000004',
    'data': '0x70a082310000000000000000000000005300000000000000000000000000000000000004'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x5300000000000000000000000000000000000004",
        "data": "0x70a082310000000000000000000000005300000000000000000000000000000000000004",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Scroll to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Scroll:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Scroll:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x5300000000000000000000000000000000000004',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/scroll/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/scroll/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/scroll/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/scroll/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Scroll RPC Method

# debug_traceTransaction - Scroll RPC Method

Traces a transaction execution on Scroll by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Scroll
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/scroll/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/scroll/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Scroll RPC Method

# eth_accounts - Scroll RPC Method

Returns a list of addresses owned by the client on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/scroll/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/scroll/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Scroll RPC Method

# eth_blockNumber - Scroll RPC Method

Returns the number of the most recent block on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_blockNumber` is fundamental for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Syncing Applications** - Keep your dApp in sync with the latest Scroll blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Scroll block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Scroll block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Scroll block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Scroll block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Scroll block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Scroll:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Scroll:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Scroll node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/scroll/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/scroll/eth_syncing) - Check if node is still syncing

---

## eth_call - Scroll RPC Method

# eth_call - Scroll RPC Method

Executes a new message call immediately without creating a transaction on Scroll. Used for reading smart contract state.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

The `eth_call` method serves these key scenarios for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Scroll
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5300000000000000000000000000000000000004';
const walletAddress = '0x5300000000000000000000000000000000000004';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Scroll. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x5300000000000000000000000000000000000004';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x5300000000000000000000000000000000000004';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Scroll
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Scroll

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x5300000000000000000000000000000000000004",
      "data": "0x70a082310000000000000000000000005300000000000000000000000000000000000004"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x5300000000000000000000000000000000000004",
      "data": "0x70a082310000000000000000000000005300000000000000000000000000000000000004"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x5300000000000000000000000000000000000004',
    '0x5300000000000000000000000000000000000004'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")
    data := common.FromHex("0x70a082310000000000000000000000005300000000000000000000000000000000000004")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Scroll RPC Method

# eth_chainId - Scroll RPC Method

Returns the chain ID used for transaction signing on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_chainId` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/scroll/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/scroll/eth_syncing) - Check sync status

---

## eth_coinbase - Scroll RPC Method

# eth_coinbase - Scroll RPC Method

Checks the legacy `eth_coinbase` compatibility method on Scroll. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Scroll coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Scroll coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Scroll coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Scroll coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Scroll coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Scroll nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/scroll/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/scroll/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/scroll/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Scroll RPC Method

# eth_estimateGas - Scroll RPC Method

Estimates the gas necessary to execute a transaction on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Scroll
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x5300000000000000000000000000000000000004', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x5300000000000000000000000000000000000004', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Scroll.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Scroll may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x5300000000000000000000000000000000000004',
  '0x5300000000000000000000000000000000000004',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x5300000000000000000000000000000000000004",
    "to": "0x5300000000000000000000000000000000000004",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x5300000000000000000000000000000000000004",
      "to": "0x5300000000000000000000000000000000000004",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x5300000000000000000000000000000000000004', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/scroll/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Scroll RPC Method

# eth_feeHistory - Scroll RPC Method

Returns historical gas fee data on Scroll, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Scroll without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Scroll.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Scroll) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/scroll/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/scroll/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Scroll RPC Method

# eth_gasPrice - Scroll RPC Method

Returns the current gas price on Scroll in wei.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Scroll
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Scroll. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Scroll, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Scroll: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Scroll supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/scroll/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/scroll/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Scroll RPC Method

# eth_getBalance - Scroll RPC Method

Returns the balance of a given address on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getBalance` is fundamental for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Scroll
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Scroll
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x5300000000000000000000000000000000000004",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Scroll. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Scroll`);
  return balance;
}

displayBalance('0x5300000000000000000000000000000000000004');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Scroll at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x5300000000000000000000000000000000000004'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Scroll')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Scroll')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Scroll.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x5300000000000000000000000000000000000004")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x5300000000000000000000000000000000000004",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x5300000000000000000000000000000000000004';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x5300000000000000000000000000000000000004'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5300000000000000000000000000000000000004")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/scroll/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/scroll/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Scroll RPC Method

# eth_getBlockByHash - Scroll RPC Method

Returns information about a block by hash on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getBlockByHash` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Scroll
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Scroll.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Scroll.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/scroll/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Scroll RPC Method

# eth_getBlockByNumber - Scroll RPC Method

Returns information about a block by block number on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getBlockByNumber` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Scroll
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Scroll with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Scroll. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/scroll/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/scroll/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/scroll/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Scroll RPC Method

# eth_getBlockReceipts - Scroll RPC Method

Returns all transaction receipts for a block on Scroll. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getBlockReceipts` is useful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Scroll, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Scroll. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x122ce98b8c7b63658708683fe2d01378846723641ac04459e844a61a6225db5c",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/scroll/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/scroll/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Scroll RPC Method

# eth_getCode - Scroll RPC Method

Returns the bytecode at a given address on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getCode` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Scroll
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Scroll:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Scroll:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x5300000000000000000000000000000000000004",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x5300000000000000000000000000000000000004",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x5300000000000000000000000000000000000004';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x5300000000000000000000000000000000000004'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5300000000000000000000000000000000000004")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/scroll/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/scroll/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Scroll RPC Method

# eth_getFilterChanges - Scroll RPC Method

Polls a filter on Scroll for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getFilterChanges` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Scroll
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5300000000000000000000000000000000000004',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5300000000000000000000000000000000000004'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Scroll:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/scroll/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/scroll/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/scroll/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/scroll/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/scroll/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Scroll RPC Method

# eth_getFilterLogs - Scroll RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Scroll. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getFilterLogs` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Scroll
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x5300000000000000000000000000000000000004"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x5300000000000000000000000000000000000004',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x5300000000000000000000000000000000000004'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/scroll/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/scroll/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/scroll/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/scroll/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Scroll RPC Method

# eth_getLogs - Scroll RPC Method

Returns an array of all logs matching a given filter object on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Scroll for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Scroll
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5300000000000000000000000000000000000004';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x5300000000000000000000000000000000000004';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Scroll.

```javascript
const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Scroll enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Scroll, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5300000000000000000000000000000000000004",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x5300000000000000000000000000000000000004",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x5300000000000000000000000000000000000004",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x5300000000000000000000000000000000000004',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x5300000000000000000000000000000000000004',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/scroll/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/scroll/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Scroll RPC Method

# eth_getStorageAt - Scroll RPC Method

Returns the value from a storage position at a given address on Scroll. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getStorageAt` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **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 zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **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": [
    "0x5300000000000000000000000000000000000004",
    "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-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x5300000000000000000000000000000000000004",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x5300000000000000000000000000000000000004', '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-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x5300000000000000000000000000000000000004';

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-scroll-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 = '0x5300000000000000000000000000000000000004'
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-scroll-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-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5300000000000000000000000000000000000004")
    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 Scroll:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-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-scroll-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 = '0x5300000000000000000000000000000000000004';
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 Scroll:`);
  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/scroll/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/scroll/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/scroll/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Scroll RPC Method

# eth_getTransactionByHash - Scroll RPC Method

Returns the information about a transaction by transaction hash on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getTransactionByHash` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Scroll
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Scroll. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Scroll. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/scroll/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Scroll RPC Method

# eth_getTransactionCount - Scroll RPC Method

Returns the number of transactions sent from an address on Scroll, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getTransactionCount` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Scroll
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x5300000000000000000000000000000000000004",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x5300000000000000000000000000000000000004",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x5300000000000000000000000000000000000004', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Scroll nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x5300000000000000000000000000000000000004';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x5300000000000000000000000000000000000004'
nonce = get_transaction_count(address)
print(f'Scroll nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5300000000000000000000000000000000000004")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Scroll nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Scroll:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x5300000000000000000000000000000000000004');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/scroll/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/scroll/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/scroll/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Scroll RPC Method

# eth_getTransactionReceipt - Scroll RPC Method

Returns the receipt of a transaction by transaction hash on Scroll. Receipt is only available for mined transactions.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_getTransactionReceipt` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Scroll and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Scroll. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Scroll, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x99db6a24447f261a66623dff96eb0fa15ad5a8defaadb06a5e6bfe8a7d622c1e")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/scroll/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/scroll/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Scroll RPC Method

# eth_hashrate - Scroll RPC Method

Returns the legacy `eth_hashrate` compatibility value on Scroll. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Scroll hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Scroll hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Scroll hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Scroll hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Scroll hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/scroll/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/scroll/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/scroll/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Scroll RPC Method

# eth_maxPriorityFeePerGas - Scroll RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Scroll. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Scroll
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Scroll priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Scroll priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Scroll priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Scroll:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Scroll:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/scroll/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/scroll/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/scroll/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Scroll RPC Method

# eth_mining - Scroll RPC Method

Checks the legacy `eth_mining` compatibility method on Scroll. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Scroll mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Scroll mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Scroll mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Scroll mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Scroll mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/scroll/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/scroll/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/scroll/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Scroll RPC Method

# eth_newBlockFilter - Scroll RPC Method

Creates a filter on Scroll that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_newBlockFilter` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Block Monitoring** - Detect new blocks on Scroll as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Scroll:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/scroll/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/scroll/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/scroll/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/scroll/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Scroll RPC Method

# eth_newFilter - Scroll RPC Method

Creates a filter object on Scroll based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_newFilter` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Event Monitoring** - Subscribe to specific contract events on Scroll such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5300000000000000000000000000000000000004",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x5300000000000000000000000000000000000004",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5300000000000000000000000000000000000004',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5300000000000000000000000000000000000004',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Scroll:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x5300000000000000000000000000000000000004',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/scroll/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/scroll/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/scroll/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/scroll/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/scroll/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Scroll RPC Method

# eth_newPendingTransactionFilter - Scroll RPC Method

Creates a filter on Scroll that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Mempool Monitoring** - Observe unconfirmed transactions on Scroll to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for zero-migration DeFi protocols, zkEVM-native dApps, and 100+ ecosystem projects with native Ethereum tooling

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Scroll...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Scroll:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/scroll/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/scroll/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/scroll/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Scroll RPC Method

# eth_protocolVersion - Scroll RPC Method

Returns the current Ethereum protocol version used by the Scroll node.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_protocolVersion` is useful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Scroll protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Scroll protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Scroll protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Scroll protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Scroll protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Scroll nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/scroll/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/scroll/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/scroll/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Scroll RPC Method

# eth_sendRawTransaction - Scroll RPC Method

Submits a pre-signed transaction for broadcast to Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Scroll
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x5300000000000000000000000000000000000004', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Scroll mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/scroll/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x5300000000000000000000000000000000000004")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/scroll/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/scroll/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Scroll RPC Method

# eth_sendTransaction - Scroll RPC Method

Creates and sends a new transaction from an unlocked account on Scroll. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Scroll tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Scroll tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Scroll tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Scroll tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Scroll tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Scroll dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/scroll/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/scroll/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Scroll RPC Method

# eth_signTransaction - Scroll RPC Method

Signs a transaction with the private key of the specified account on Scroll without submitting it to the network.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Scroll tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Scroll tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Scroll tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Scroll:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/scroll/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/scroll/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/scroll/eth_accounts) - List accounts available for signing

---

## eth_syncing - Scroll RPC Method

# eth_syncing - Scroll RPC Method

Returns the sync status of your Scroll node - either `false` when fully synced, or an object describing the sync progress.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_syncing` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Scroll node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Scroll node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Scroll node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/scroll/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/scroll/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/scroll/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/scroll/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Scroll RPC Method

# eth_uninstallFilter - Scroll RPC Method

Removes a filter on Scroll that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`eth_uninstallFilter` is important for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/scroll/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/scroll/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/scroll/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/scroll/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/scroll/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Scroll RPC Method

# net_listening - Scroll RPC Method

Checks whether the connected Scroll client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`net_listening` is useful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Scroll node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Scroll node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Scroll node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/scroll/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/scroll/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/scroll/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/scroll/web3_clientVersion) - Get node client info

---

## net_peerCount - Scroll RPC Method

# net_peerCount - Scroll RPC Method

Returns the number of peers currently connected to your Scroll node.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`net_peerCount` is important for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Scroll deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Scroll peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Scroll peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Scroll peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Scroll nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/scroll/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/scroll/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/scroll/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/scroll/web3_clientVersion) - Get node client info

---

## net_version - Scroll RPC Method

# net_version - Scroll RPC Method

Returns the current network ID on Scroll as a decimal string. The network ID identifies which network the node is connected to.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`net_version` is essential for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Endpoint Identification** - Confirm your application is connected to the expected Scroll network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Scroll network ID:', networkId);

// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Scroll network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Scroll network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/scroll/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/scroll/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/scroll/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/scroll/eth_syncing) - Check node sync progress

---

## rpc_modules - Scroll RPC Method

# rpc_modules - Scroll RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Scroll endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`rpc_modules` is useful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/scroll/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/scroll/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Scroll RPC Method

# web3_clientVersion - Scroll RPC Method

Returns the current client software version string for your Scroll node, including the client name, version number, OS, and runtime.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

## When to Use This Method

`web3_clientVersion` is valuable for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Scroll client:', clientVersion);

// Using fetch
const response = await fetch('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Scroll client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Scroll client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/scroll/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/scroll/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/scroll/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/scroll/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Scroll RPC Method

# web3_sha3 - Scroll RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Scroll.

> **Why Scroll?** Build on the largest zkEVM by market share with $750M+ TVL and bytecode-level Ethereum equivalence with bytecode-level EVM equivalence, native Hardhat/Remix/MetaMask support, decentralized proof validation, and Scroll SDK for L2/L3 deployment.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for Ethereum developers, DeFi builders, and teams requiring seamless mainnet migration:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-scroll-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/scroll/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/scroll/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/scroll/web3_clientVersion) - Get node client version

---

## Sonic - Fastest EVM Layer-1 Documentation

# Sonic - Fastest EVM Layer-1 Documentation

## Sonic RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Sonic supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Sonic?

Sonic is the highest-performing EVM Layer-1 blockchain, evolved from Fantom, designed to power the next generation of DeFi applications. Combining unprecedented speed with developer-first incentives, Sonic offers:

### **Unmatched Performance**

- **400,000 TPS capability** - Theoretical throughput that sets new industry standards
- **Sub-second finality** - Get instant transaction confirmations
- **10,000 verifiable TPS** - Real-world performance with near-instant settlement

### **Revolutionary Fee Monetization**

- **90% fee rebates** - Developers earn up to 90% of transaction fees through FeeM
- **Sustainable revenue model** - Web2-like monetization for Web3 applications
- **Developer incentives** - 200M S tokens allocated through Innovator Fund

### **Advanced Technology Stack**

- **SonicVM optimization** - Super instructions that accelerate smart contract execution
- **SonicDB efficiency** - 96% reduction in node operating costs
- **Full EVM compatibility** - Deploy existing Ethereum apps without code changes

## Quick Start with Sonic

Connect to Sonic in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Sonic mainnet
const provider = new JsonRpcProvider(
  'https://api-sonic-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Sonic mainnet
const web3 = new Web3(
  'https://api-sonic-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Sonic:', chainId === 146);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { defineChain } from 'viem';

// Define Sonic chain
const sonic = defineChain({
  id: 146,
  name: 'Sonic',
  nativeCurrency: {
    decimals: 18,
    name: 'Sonic',
    symbol: 'S',
  },
  rpcUrls: {
    default: {
      http: ['https://api-sonic-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
});

// Create Sonic client
const client = createPublicClient({
  chain: sonic,
  transport: http('https://api-sonic-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

## Network Information

| Parameter    | Value      | Details      |
| ------------ | ---------- | ------------ |
| Chain ID     | 146        | Mainnet      |
| Block Time   | < 1 second | Average      |
| Gas Token    | S          | Native token |
| RPC Standard | Ethereum   | JSON-RPC 2.0 |

## API Reference

Sonic supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/). Access all standard methods with industry-leading performance.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation with sub-second finality
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Sonic's fast finality means confirmations are near-instant
  console.log('Transaction confirmed in block:', receipt.blockNumber);

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on Sonic:

```javascript
// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Get current gas price
const gasPrice = await provider.getGasPrice();

// Total cost in S tokens
const totalCost = gasEstimate * gasPrice;
console.log('Transaction cost:', totalCost, 'S');
```

### Event Filtering

Efficiently query contract events with Sonic's high throughput:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 10000; // Sonic can handle larger batches

  const currentBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class SonicProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-sonic-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for transaction"

Ensure your account has enough S tokens for gas fees:

```javascript
// Check balance before sending transaction
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more S tokens`);
}
```

### Error: "Transaction underpriced"

Sonic supports EIP-1559 pricing. Always use dynamic gas pricing:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## FAQs

### How do I migrate from Fantom to Sonic?

Sonic is a direct evolution of Fantom with a 1:1 token swap from FTM to S. Your existing Fantom applications can be deployed on Sonic with minimal changes - just update your RPC endpoint and chain ID.

### What makes Sonic different from other L1s?

Sonic combines industry-leading performance (400k TPS capability) with unique developer incentives through Fee Monetization (FeeM), where developers earn up to 90% of transaction fees generated by their dApps.

### Is Sonic compatible with existing Ethereum tools?

Yes! Sonic is fully EVM-compatible and works with all Ethereum tooling including MetaMask, Hardhat, Foundry, Truffle, and more. Simply configure them with Sonic's chain ID (146) and RPC endpoint.

## Smoke Tests

Verify your Sonic integration with these quick tests:

```javascript
// Test 1: Check connection
const chainId = await provider.getNetwork();
console.assert(chainId.chainId === 146n, 'Connected to Sonic mainnet');

// Test 2: Query recent block
const block = await provider.getBlock('latest');
console.log('Current block:', block.number);

// Test 3: Check USDC contract
const usdcAddress = '0x29219dd400f2Bf60E5a23d13Be72B486D4038894';
const code = await provider.getCode(usdcAddress);
console.assert(code !== '0x', 'USDC contract exists');
```

## Migration Guide

### From Fantom Opera

Migrating from Fantom Opera to Sonic is straightforward:

```javascript
// Before (Fantom)
const provider = new JsonRpcProvider('https://rpc.ftm.tools');

// After (Sonic)
const provider = new JsonRpcProvider(
  'https://api-sonic-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (146 vs 250)
// Note: New native token (S instead of FTM)
// 1:1 token swap available
```

## Resources & Tools

### Official Resources

- [Sonic Documentation](https://docs.soniclabs.com)
- [Sonic Bridge](https://my.soniclabs.com/bridge)
- [Sonic Explorer](https://sonicscan.org)

### Developer Tools

- [Build on Sonic](https://docs.soniclabs.com/sonic/build-on-sonic)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Sonic with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Sonic RPC Method

# debug_traceBlock - Sonic RPC Method

Traces all transactions in a block on Sonic by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Sonic - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Sonic
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Sonic:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Sonic blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/sonic/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/sonic/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/sonic/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/sonic/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Sonic RPC Method

# debug_traceBlockByHash - Sonic RPC Method

Traces all transactions in a block on Sonic identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Sonic - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Sonic
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Sonic:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Sonic:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/sonic/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/sonic/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/sonic/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/sonic/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/sonic/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Sonic RPC Method

# debug_traceBlockByNumber - Sonic RPC Method

Traces all transactions in a block on Sonic identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Sonic - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Sonic execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Sonic:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Sonic:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/sonic/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/sonic/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/sonic/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/sonic/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Sonic RPC Method

# debug_traceCall - Sonic RPC Method

Traces a call on Sonic without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Sonic - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Sonic
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
        "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
        "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    data: '0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    data: '0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    'data': '0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
        "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Sonic to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Sonic:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Sonic:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/sonic/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/sonic/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/sonic/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/sonic/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Sonic RPC Method

# debug_traceTransaction - Sonic RPC Method

Traces a transaction execution on Sonic by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Sonic
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/sonic/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/sonic/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Sonic RPC Method

# eth_accounts - Sonic RPC Method

Returns a list of addresses owned by the client on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/sonic/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/sonic/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Sonic RPC Method

# eth_blockNumber - Sonic RPC Method

Returns the number of the most recent block on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Syncing Applications** - Keep your dApp in sync with the latest Sonic blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Sonic block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Sonic block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Sonic block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Sonic block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Sonic block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Sonic:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Sonic:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Sonic node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/sonic/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/sonic/eth_syncing) - Check if node is still syncing

---

## eth_call - Sonic RPC Method

# eth_call - Sonic RPC Method

Executes a new message call immediately without creating a transaction on Sonic. Used for reading smart contract state.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Sonic
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';
const walletAddress = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Sonic. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Sonic
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Sonic

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    data := common.FromHex("0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Sonic RPC Method

# eth_chainId - Sonic RPC Method

Returns the chain ID used for transaction signing on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/sonic/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/sonic/eth_syncing) - Check sync status

---

## eth_coinbase - Sonic RPC Method

# eth_coinbase - Sonic RPC Method

Checks the legacy `eth_coinbase` compatibility method on Sonic. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Sonic coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Sonic coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Sonic coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Sonic coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Sonic coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Sonic nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/sonic/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/sonic/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/sonic/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Sonic RPC Method

# eth_estimateGas - Sonic RPC Method

Estimates the gas necessary to execute a transaction on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Sonic
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Sonic.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Sonic may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/sonic/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Sonic RPC Method

# eth_feeHistory - Sonic RPC Method

Returns historical gas fee data on Sonic, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Sonic without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Sonic.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Sonic) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/sonic/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/sonic/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Sonic RPC Method

# eth_gasPrice - Sonic RPC Method

Returns the current gas price on Sonic in wei.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Sonic
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Sonic. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Sonic, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Sonic: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Sonic supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/sonic/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/sonic/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Sonic RPC Method

# eth_getBalance - Sonic RPC Method

Returns the balance of a given address on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Sonic
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Sonic
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Sonic. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Sonic`);
  return balance;
}

displayBalance('0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Sonic at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Sonic')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Sonic')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Sonic.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/sonic/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/sonic/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Sonic RPC Method

# eth_getBlockByHash - Sonic RPC Method

Returns information about a block by hash on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Sonic
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Sonic.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Sonic.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Sonic RPC Method

# eth_getBlockByNumber - Sonic RPC Method

Returns information about a block by block number on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Sonic
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Sonic with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Sonic. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/sonic/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/sonic/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Sonic RPC Method

# eth_getBlockReceipts - Sonic RPC Method

Returns all transaction receipts for a block on Sonic. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Sonic, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Sonic. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x71fa53a73a4b77921b6f91b6ae19f552fc27aab47f9778a29a5044e93778f122",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/sonic/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/sonic/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Sonic RPC Method

# eth_getCode - Sonic RPC Method

Returns the bytecode at a given address on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Sonic
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Sonic:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Sonic:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/sonic/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/sonic/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Sonic RPC Method

# eth_getFilterChanges - Sonic RPC Method

Polls a filter on Sonic for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Sonic
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Sonic:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/sonic/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/sonic/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/sonic/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/sonic/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/sonic/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Sonic RPC Method

# eth_getFilterLogs - Sonic RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Sonic. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Sonic
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/sonic/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/sonic/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/sonic/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/sonic/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Sonic RPC Method

# eth_getLogs - Sonic RPC Method

Returns an array of all logs matching a given filter object on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Sonic for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Sonic
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Sonic.

```javascript
const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Sonic enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Sonic, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/sonic/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/sonic/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Sonic RPC Method

# eth_getStorageAt - Sonic RPC Method

Returns the value from a storage position at a given address on Sonic. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **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 ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **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": [
    "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "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-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38', '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-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';

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-sonic-mainnet-archive.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 = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
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-sonic-mainnet-archive.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-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    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 Sonic:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.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-sonic-mainnet-archive.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 = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';
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 Sonic:`);
  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/sonic/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/sonic/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/sonic/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Sonic RPC Method

# eth_getTransactionByHash - Sonic RPC Method

Returns the information about a transaction by transaction hash on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Sonic
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Sonic. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Sonic. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/sonic/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Sonic RPC Method

# eth_getTransactionCount - Sonic RPC Method

Returns the number of transactions sent from an address on Sonic, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Sonic
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Sonic nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
nonce = get_transaction_count(address)
print(f'Sonic nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Sonic nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Sonic:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/sonic/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/sonic/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/sonic/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Sonic RPC Method

# eth_getTransactionReceipt - Sonic RPC Method

Returns the receipt of a transaction by transaction hash on Sonic. Receipt is only available for mined transactions.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Sonic and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Sonic. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Sonic, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/sonic/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/sonic/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Sonic RPC Method

# eth_hashrate - Sonic RPC Method

Returns the legacy `eth_hashrate` compatibility value on Sonic. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Sonic hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Sonic hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Sonic hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Sonic hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Sonic hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/sonic/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/sonic/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Sonic RPC Method

# eth_maxPriorityFeePerGas - Sonic RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Sonic. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Sonic
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Sonic priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Sonic priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Sonic priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Sonic:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Sonic:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/sonic/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/sonic/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/sonic/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Sonic RPC Method

# eth_mining - Sonic RPC Method

Checks the legacy `eth_mining` compatibility method on Sonic. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Sonic mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Sonic mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Sonic mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Sonic mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Sonic mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/sonic/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/sonic/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Sonic RPC Method

# eth_newBlockFilter - Sonic RPC Method

Creates a filter on Sonic that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Block Monitoring** - Detect new blocks on Sonic as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Sonic:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/sonic/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/sonic/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/sonic/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Sonic RPC Method

# eth_newFilter - Sonic RPC Method

Creates a filter object on Sonic based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Event Monitoring** - Subscribe to specific contract events on Sonic such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Sonic:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/sonic/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/sonic/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/sonic/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/sonic/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/sonic/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Sonic RPC Method

# eth_newPendingTransactionFilter - Sonic RPC Method

Creates a filter on Sonic that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Mempool Monitoring** - Observe unconfirmed transactions on Sonic to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Sonic...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Sonic:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/sonic/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/sonic/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/sonic/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Sonic RPC Method

# eth_protocolVersion - Sonic RPC Method

Returns the current Ethereum protocol version used by the Sonic node.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Sonic protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Sonic protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Sonic protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
print(f'Sonic protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Sonic protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Sonic nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/sonic/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/sonic/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/sonic/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Sonic RPC Method

# eth_sendRawTransaction - Sonic RPC Method

Submits a pre-signed transaction for broadcast to Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Sonic
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Sonic mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/sonic/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/sonic/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/sonic/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Sonic RPC Method

# eth_sendTransaction - Sonic RPC Method

Creates and sends a new transaction from an unlocked account on Sonic. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Sonic tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Sonic tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Sonic tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Sonic tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Sonic tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Sonic dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/sonic/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/sonic/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Sonic RPC Method

# eth_signTransaction - Sonic RPC Method

Signs a transaction with the private key of the specified account on Sonic without submitting it to the network.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Sonic tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Sonic tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Sonic tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Sonic:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/sonic/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/sonic/eth_accounts) - List accounts available for signing

---

## eth_syncing - Sonic RPC Method

# eth_syncing - Sonic RPC Method

Returns the sync status of your Sonic node - either `false` when fully synced, or an object describing the sync progress.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Sonic node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Sonic node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Sonic node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/sonic/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/sonic/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/sonic/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Sonic RPC Method

# eth_uninstallFilter - Sonic RPC Method

Removes a filter on Sonic that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/sonic/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/sonic/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/sonic/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/sonic/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/sonic/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Sonic RPC Method

# net_listening - Sonic RPC Method

Checks whether the connected Sonic client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`net_listening` is useful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Sonic node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Sonic node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Sonic node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/sonic/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/sonic/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/sonic/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/sonic/web3_clientVersion) - Get node client info

---

## net_peerCount - Sonic RPC Method

# net_peerCount - Sonic RPC Method

Returns the number of peers currently connected to your Sonic node.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`net_peerCount` is important for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Sonic deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Sonic peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Sonic peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Sonic peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Sonic nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/sonic/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/sonic/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/sonic/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/sonic/web3_clientVersion) - Get node client info

---

## net_version - Sonic RPC Method

# net_version - Sonic RPC Method

Returns the current network ID on Sonic as a decimal string. The network ID identifies which network the node is connected to.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`net_version` is essential for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Endpoint Identification** - Confirm your application is connected to the expected Sonic network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Sonic network ID:', networkId);

// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Sonic network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Sonic network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/sonic/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/sonic/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/sonic/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/sonic/eth_syncing) - Check node sync progress

---

## rpc_modules - Sonic RPC Method

# rpc_modules - Sonic RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Sonic endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/sonic/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/sonic/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/sonic/trace_transaction) - Trace namespace example

---

## trace_block - Sonic RPC Method

# trace_block - Sonic RPC Method

Returns traces for all transactions in a block on Sonic.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Sonic
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Sonic chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/sonic/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/sonic/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/sonic/trace_get) - Get a specific trace by index

---

## trace_call - Sonic RPC Method

# trace_call - Sonic RPC Method

Traces a call without creating a transaction on Sonic, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Sonic
- **Pre-execution analysis** - Test contract interactions without spending gas for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38",
      "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38", "data": "0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
    data: '0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
        'data': '0x70a08231000000000000000000000000039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/sonic/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/sonic/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/sonic/trace_transaction) - Trace a specific transaction

---

## trace_filter - Sonic RPC Method

# trace_filter - Sonic RPC Method

Returns traces matching a filter on Sonic.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Sonic
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/sonic/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/sonic/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/sonic/eth_getLogs) - Filter event logs

---

## trace_get - Sonic RPC Method

# trace_get - Sonic RPC Method

Returns a trace at a specific position within a transaction on Sonic.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Sonic
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/sonic/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/sonic/trace_block) - Get all traces in a block

---

## trace_transaction - Sonic RPC Method

# trace_transaction - Sonic RPC Method

Returns all traces for a specific transaction on Sonic.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for ultra-fast DeFi, high-frequency trading dApps, and performance-critical applications
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Sonic
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0xac0f2115a24c6f7b52989a17a8b0f8a6013a0d84df3ba93254fc26a116508938'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/sonic/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/sonic/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/sonic/trace_filter) - Filter traces by criteria

---

## txpool_content - Sonic RPC Method

# txpool_content - Sonic RPC Method

Returns the full pending and queued transaction pool for the connected Sonic endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`txpool_content` is useful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/sonic/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/sonic/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/sonic/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Sonic RPC Method

# txpool_status - Sonic RPC Method

Returns transaction pool counters for the connected Sonic endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`txpool_status` is valuable for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/sonic/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/sonic/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/sonic/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Sonic RPC Method

# web3_clientVersion - Sonic RPC Method

Returns the current client software version string for your Sonic node, including the client name, version number, OS, and runtime.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Sonic client:', clientVersion);

// Using fetch
const response = await fetch('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Sonic client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Sonic client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/sonic/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/sonic/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/sonic/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/sonic/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Sonic RPC Method

# web3_sha3 - Sonic RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Sonic.

> **Why Sonic?** Build on the world's fastest EVM chain with 720ms finality, $1.2B+ TVL, and 1,534% growth since launch with 720ms transaction finality, 10K TPS, 90% fee sharing via FeeM, Fantom heritage with Andre Cronje leadership.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, high-frequency trading builders, and teams requiring sub-second finality:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-sonic-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/sonic/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/sonic/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/sonic/web3_clientVersion) - Get node client version

---

## Starknet - Cairo-Powered Validity Rollup Documentation

# Starknet - Cairo-Powered Validity Rollup Documentation

## Starknet RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Starknet supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Starknet?

Starknet is the leading validity rollup (zk-rollup) that executes Cairo smart contracts with STARK proof security, offering unparalleled scalability while maintaining Ethereum-grade security:

### **Revolutionary Cairo Performance**

- **Native account abstraction** - Every account is a programmable smart contract
- **Cairo VM execution** - Provable computation with mathematical guarantees
- **Sub-second finality** - Fast transaction confirmation with L1 security
- **99%+ cost reduction** compared to Ethereum mainnet

### **STARK Proof Security**

- **Zero-knowledge proofs** - Cryptographically secure state transitions
- **Ethereum settlement** - Inherits L1 security with validity proof verification
- **Decentralized proving** - Robust network with permissionless participation

### **Developer-First Ecosystem**

- **Cairo language** - Safe, powerful programming language for contracts
- **Rich tooling** - starknet.js, starknet.py, Protostar, Scarb, and more
- **Growing DeFi** - Leading protocols like Avnu, Ekubo, Nostra, JediSwap
- **Account abstraction native** - Flexible wallet experiences out of the box

## Quick Start with Starknet

Connect to Starknet in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Direct JSON-RPC
starknet.js
starknet.py
Scarb & Cairo

```bash
# Get latest block number
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_blockNumber",
    "params": [],
    "id": 1
  }'

# Get chain ID
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_chainId",
    "params": [],
    "id": 1
  }'

# Call a contract function (ETH balance)
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_call",
    "params": [
      {
        "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e",
        "calldata": ["0x1234..."]
      },
      "latest"
    ],
    "id": 1
  }'
```

```typescript
import { RpcProvider, Contract, Account, CallData } from 'starknet';

// Connect to Starknet mainnet
const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY'
});

// Verify connection and get network info
const chainId = await provider.getChainId();
console.log('Connected to Starknet chain ID:', chainId);

// Get the latest block
const block = await provider.getBlockWithTxs('latest');
console.log('Latest block number:', block.block_number);
console.log('Block hash:', block.block_hash);

// Query account balance (ETH contract on Starknet)
const ethAddress = '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7';
const accountAddress = '0x1234...'; // Your account address

const { result } = await provider.callContract({
  contractAddress: ethAddress,
  entrypoint: 'balanceOf',
  calldata: CallData.compile([accountAddress])
});

console.log('ETH balance:', result[0]);
```

```python
import asyncio
from starknet_py.net.full_node_client import FullNodeClient
from starknet_py.contract import Contract
from starknet_py.net.models import StarknetChainId

async def main():
    # Connect to Starknet mainnet
    client = FullNodeClient(
        node_url="https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"
    )

    # Verify connection
    chain_id = await client.get_chain_id()
    print(f"Connected to chain ID: {chain_id}")

    # Get latest block
    block = await client.get_block_with_txs(block_number="latest")
    print(f"Latest block: {block.block_number}")

    # Query contract (ETH token balance)
    eth_address = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
    account_address = "0x1234..."  # Your account address

    call_result = await client.call_contract(
        call={
            "contract_address": eth_address,
            "entry_point_selector": "balanceOf",
            "calldata": [account_address]
        }
    )

    print(f"ETH balance: {call_result}")

# Run the async function
asyncio.run(main())
```

```bash
# Initialize a new Cairo project with Scarb
scarb new my_starknet_contract
cd my_starknet_contract

# Add Starknet dependencies to Scarb.toml
cat >> Scarb.toml << EOF

[[target.starknet-contract]]
sierra = true
casm = true

[dependencies]
starknet = ">=2.6.3"
EOF

# Create a simple contract
cat > src/lib.cairo << 'EOF'
#[starknet::interface]
trait IHelloStarknet<TContractState> {
    fn increase_balance(ref self: TContractState, amount: felt252);
    fn get_balance(self: @TContractState) -> felt252;
}

#[starknet::contract]
mod HelloStarknet {
    #[storage]
    struct Storage {
        balance: felt252,
    }

    #[abi(embed_v0)]
    impl HelloStarknetImpl of super::IHelloStarknet<ContractState> {
        fn increase_balance(ref self: ContractState, amount: felt252) {
            self.balance.write(self.balance.read() + amount);
        }

        fn get_balance(self: @ContractState) -> felt252 {
            self.balance.read()
        }
    }
}
EOF

# Build the contract
scarb build
```

## Network Information

| Parameter     | Value        | Details                 |
| ------------- | ------------ | ----------------------- |
| Chain ID      | SN\_MAIN     | 0x534e5f4d41494e        |
| Block Time    | \~10 seconds | STARK proof batches     |
| Native Token  | ETH          | Fee token               |
| Account Model | AA Native    | Smart contract accounts |

### Network Details

| Parameter                  | Value                                              | Details |
| -------------------------- | -------------------------------------------------- | ------- |
| Mainnet Chain ID           | `0x534e5f4d41494e` (`SN_MAIN`)                     |         |
| Testnet (Sepolia) Chain ID | `0x534e5f5345504f4c4941` (`SN_SEPOLIA`)            |         |
| Fee Tokens                 | ETH (primary), STRK (governance, future staking)   |         |
| Finality                   | L2 confirmation (\~10s), L1 finality (\~1-4 hours) |         |
| TPS                        | 50+ current, 100+ roadmap with parallel execution  |         |

## API Reference

Starknet implements its own JSON-RPC namespace (`starknet_*`) with Cairo-specific functionality. Access all Starknet methods with STARK proof security.

## Common Integration Patterns

### Account Management

```typescript
import { Account, RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY'
});

const account = new Account(provider, accountAddress, privateKey);
const nonce = await account.getNonce();
```

### Token Operations

```typescript
// Get token balance
const { result } = await provider.callContract({
  contractAddress: tokenAddress,
  entrypoint: 'balanceOf',
  calldata: [accountAddress]
});
```

### Contract Calls

```typescript
// Execute contract function
const call = {
  contractAddress: contractAddress,
  entrypoint: functionName,
  calldata: [param1, param2]
};

const { transaction_hash } = await account.execute(call);
```

## Resources & Tools

### Official Resources

- [Starknet Documentation](https://docs.starknet.io/)
- [Cairo Language Guide](https://book.cairo-lang.org/)
- [Starknet JSON-RPC Spec](https://github.com/starkware-libs/starknet-specs)

### Block Explorers

- [Voyager Explorer](https://voyager.online/) - Comprehensive block explorer
- [Starkscan](https://starkscan.co/) - Alternative explorer with rich features

### Developer Tools

- [Starknet.js](https://www.starknetjs.com/) - TypeScript SDK
- [Starknet.py](https://github.com/software-mansion/starknet.py) - Python SDK
- [Scarb](https://docs.swmansion.com/scarb/) - Cairo package manager
- [Starknet Foundry](https://foundry-rs.github.io/starknet-foundry/) - Testing framework
- [Protostar](https://docs.swmansion.com/protostar/) - Cairo development toolchain

### Ecosystem Projects

- [Avnu](https://www.avnu.fi/) - DEX aggregator
- [Ekubo Protocol](https://ekubo.org/) - Concentrated liquidity AMM
- [Nostra](https://nostra.finance/) - Money market protocol

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Community**: [Starknet Discord](https://discord.gg/qypnmzkhbc)

***

*Start building on Starknet with Cairo-powered smart contracts using Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## starknet_blockHashAndNumber - Get the most...

# starknet_blockHashAndNumber - Get the most...

Get the most recent accepted block hash and number

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_blockHashAndNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The latest block hash and number Object with latest block hash and number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message             |
| ---- | ------------------- |
| 32   | There are no blocks |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_blockHashAndNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_blockHashAndNumber',
  params: []
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_blockNumber - Get the most recent...

# starknet_blockNumber - Get the most recent...

Get the most recent accepted block number

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The latest block number Latest block number (integer)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message             |
| ---- | ------------------- |
| 32   | There are no blocks |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_blockNumber',
  params: []
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_call - Execute Cairo Contract Calls

# starknet_call - Execute Cairo Contract Calls

Executes a function call on a Cairo smart contract without creating a transaction on the blockchain.

## Request Parameters

- `request` (`object, required`): Function call details with `contract_address` (felt252), `entry_point_selector` (felt252), and `calldata` (felt252[])
- `block_id` (`string, required`): Block reference: `"latest"`, `"l1_accepted"`, block hash, or block number

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_call",
  "params": [
    {
      "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
      "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e",
      "calldata": ["0x1234567890abcdef1234567890abcdef12345678"]
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): `ARRAY` - Array of field elements returned by the function call.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_call",
    "params": [
      {
        "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e",
        "calldata": ["0x1234567890abcdef1234567890abcdef12345678"]
      },
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY'
});

const result = await provider.callContract({
  contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
  entrypoint: 'balanceOf',
  calldata: ['0x1234567890abcdef1234567890abcdef12345678']
});
```

```python
from starknet_py.net.full_node_client import FullNodeClient

client = FullNodeClient(
    node_url="https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"
)

result = await client.call_contract(
    call={
        "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "entry_point_selector": "balanceOf",
        "calldata": ["0x1234567890abcdef1234567890abcdef12345678"]
    },
    block_id="latest"
)
```

---

## starknet_chainId - Get Starknet Chain ID

# starknet_chainId - Get Starknet Chain ID

Returns the currently configured Starknet chain ID as a hex-encoded felt252 value. This method is used to verify which Starknet network a node is connected to before signing transactions or deploying contracts.

## Overview

Starknet chain IDs are encoded as felt252 values representing short ASCII strings. Unlike EVM chains that use numeric IDs, Starknet encodes human-readable network names into their felt representation. This is consistent with Starknet's use of felt252 as the fundamental data type in the Cairo language and the StarkNet OS.

### Known Starknet Chain IDs

| Network         | Chain ID (ASCII) | Chain ID (Hex felt252)   |
| --------------- | ---------------- | ------------------------ |
| Mainnet         | `SN_MAIN`        | `0x534e5f4d41494e`       |
| Sepolia Testnet | `SN_SEPOLIA`     | `0x534e5f5345504f4c4941` |

The hex values are the ASCII byte representations of the network name strings.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`FELT, required`): The chain ID as a hex-encoded felt252 value

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x534e5f4d41494e"
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

## Examples

cURL
JavaScript
Python
Go

```bash
# Get the chain ID
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_chainId",
    "params": [],
    "id": 1
  }'

# Decode the chain ID to ASCII
curl -s -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_chainId",
    "params": [],
    "id": 1
  }' | jq -r '.result' | python3 -c "import sys; h=sys.stdin.read().strip()[2:]; print(bytes.fromhex(h).decode())"
```

```javascript
import { RpcProvider, constants } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

// Get chain ID using starknet.js
const chainId = await provider.getChainId();
console.log('Chain ID (hex):', chainId);

// Decode felt252 to readable string
function feltToString(felt) {
  const hex = felt.replace('0x', '');
  let str = '';
  for (let i = 0; i < hex.length; i += 2) {
    str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
  }
  return str;
}

const networkName = feltToString(chainId);
console.log('Network:', networkName);

// Verify correct network before proceeding
if (chainId === constants.StarknetChainId.SN_MAIN) {
  console.log('Connected to Starknet Mainnet');
} else if (chainId === constants.StarknetChainId.SN_SEPOLIA) {
  console.log('Connected to Starknet Sepolia');
} else {
  console.warn('Connected to unknown network:', networkName);
}

// Network guard for transaction signing
async function assertMainnet(provider) {
  const id = await provider.getChainId();
  if (id !== constants.StarknetChainId.SN_MAIN) {
    throw new Error(`Expected mainnet, got ${feltToString(id)}`);
  }
}
```

```python
import requests

url = "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

payload = {
    "jsonrpc": "2.0",
    "method": "starknet_chainId",
    "params": [],
    "id": 1
}

response = requests.post(url, json=payload)
chain_id_hex = response.json()["result"]

print(f"Chain ID (hex): {chain_id_hex}")

# Decode felt252 to ASCII string
chain_id_bytes = bytes.fromhex(chain_id_hex[2:])
network_name = chain_id_bytes.decode("ascii")
print(f"Network: {network_name}")

# Network verification
KNOWN_NETWORKS = {
    "0x534e5f4d41494e": "Starknet Mainnet",
    "0x534e5f5345504f4c4941": "Starknet Sepolia",
}

network = KNOWN_NETWORKS.get(chain_id_hex, "Unknown")
print(f"Connected to: {network}")

if chain_id_hex != "0x534e5f4d41494e":
    print("WARNING: Not connected to Starknet Mainnet")
```

```go
package main

import (
    "bytes"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    url := "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

    body := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "starknet_chainId",
        "params":  []interface{}{},
        "id":      1,
    }

    jsonBody, _ := json.Marshal(body)
    resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    respBody, _ := io.ReadAll(resp.Body)

    var result map[string]interface{}
    json.Unmarshal(respBody, &result)

    chainIDHex := result["result"].(string)
    fmt.Printf("Chain ID (hex): %s\n", chainIDHex)

    // Decode felt252 to ASCII
    decoded, _ := hex.DecodeString(chainIDHex[2:])
    fmt.Printf("Network: %s\n", string(decoded))
}
```

## Use Cases

- **Network Verification** - Confirm you are connected to mainnet or testnet before signing transactions with an Account contract
- **Multi-Network Applications** - Route requests to the correct network handler based on chain ID
- **Transaction Signing** - Include the correct chain ID in transaction signatures to prevent cross-network replays
- **Wallet Integrations** - Display the connected Starknet network in wallet UIs
- **Deployment Pipelines** - Gate contract deployments on the correct target network

## Related Methods

- [starknet\_specVersion](https://www.dwellir.com/docs/starknet/starknet_specVersion) - Get the supported Starknet JSON-RPC spec version
- [starknet\_syncing](https://www.dwellir.com/docs/starknet/starknet_syncing) - Check node synchronization status
- [starknet\_blockNumber](https://www.dwellir.com/docs/starknet/starknet_blockNumber) - Get the latest block number
- [starknet\_blockHashAndNumber](https://www.dwellir.com/docs/starknet/starknet_blockHashAndNumber) - Get latest block hash and number

---

## starknet_estimateFee - Estimate Transaction...

# starknet_estimateFee - Estimate Transaction...

Estimates the resources and fees required for executing a sequence of transactions on Starknet.

## Request Parameters

- `request` (`array, required`): Array of transactions to estimate
- `simulation_flags` (`array, required`): Optional simulation parameters (`SKIP_VALIDATE` to skip validation phase)
- `block_id` (`string, required`): Block reference: `"latest"` (most recent block), block hash, or block number

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_estimateFee",
  "params": [
    [
      {
        "type": "INVOKE",
        "sender_address": "0x1234567890abcdef1234567890abcdef12345678",
        "calldata": [
          "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
          "0x83afdfe4cdc632f4b21f8bdebabc13e47c1f1b4b97fc8b5b4b1c4e6746a3a7e0",
          "0x3",
          "0x2386f26fc10000",
          "0x0",
          "0x456789abcdef456789abcdef456789ab"
        ],
        "version": "0x3",
        "signature": ["0x0"],
        "nonce": "0x1"
      }
    ],
    ["SKIP_VALIDATE"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): `overall_fee` - Total fee in wei (felt252) `gas_consumed` - Total gas consumed (felt252) `gas_price` - Gas price in wei per unit (felt252)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_estimateFee",
    "params": [
      [
        {
          "type": "INVOKE",
          "sender_address": "0x1234567890abcdef1234567890abcdef12345678",
          "calldata": [
            "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
            "0x83afdfe4cdc632f4b21f8bdebabc13e47c1f1b4b97fc8b5b4b1c4e6746a3a7e0",
            "0x3",
            "0xde0b6b3a7640000",
            "0x0",
            "0x456789abcdef456789abcdef456789ab"
          ],
          "version": "0x3",
          "signature": ["0x0"],
          "nonce": "0x1"
        }
      ],
      ["SKIP_VALIDATE"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY'
});

const transaction = {
  type: "INVOKE",
  sender_address: "0x1234567890abcdef1234567890abcdef12345678",
  calldata: [
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
    "0x83afdfe4cdc632f4b21f8bdebabc13e47c1f1b4b97fc8b5b4b1c4e6746a3a7e0",
    "0x3",
    "0xde0b6b3a7640000",
    "0x0",
    "0x456789abcdef456789abcdef456789ab"
  ],
  version: "0x3",
  signature: ["0x0"],
  nonce: "0x1"
};

const estimate = await provider.estimateFee([transaction], ["SKIP_VALIDATE"], "latest");
console.log(estimate);
```

```python
from starknet_py.net.full_node_client import FullNodeClient

client = FullNodeClient(
    node_url="https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"
)

transaction = {
    "type": "INVOKE",
    "sender_address": "0x1234567890abcdef1234567890abcdef12345678",
    "calldata": [
        "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "0x83afdfe4cdc632f4b21f8bdebabc13e47c1f1b4b97fc8b5b4b1c4e6746a3a7e0",
        "0x3",
        "0xde0b6b3a7640000",
        "0x0",
        "0x456789abcdef456789abcdef456789ab"
    ],
    "version": "0x3",
    "signature": ["0x0"],
    "nonce": "0x1"
}

estimate = await client.estimate_fee(
    tx=transaction,
    simulation_flags=["SKIP_VALIDATE"],
    block_id="latest"
)
print(estimate)
```

---

## starknet_estimateMessageFee - Estimate L1-to-L2 Message Fee

# starknet_estimateMessageFee - Estimate L1-to-L2 Message Fee

Estimates the L2 fee required to process a message sent from Ethereum (L1) to Starknet (L2). This method simulates the `l1_handler` transaction that would be triggered by the L1 message and returns the estimated gas and fee breakdown.

## Overview

Starknet's L1-to-L2 messaging allows Ethereum smart contracts to send messages to Starknet contracts. When a message is sent from L1, the Starknet sequencer creates an `l1_handler` transaction to execute the corresponding function on the L2 contract. This method estimates the resources and fees required for that L2 execution.

This is important for bridge operators, cross-layer DeFi protocols, and any application that sends messages from Ethereum to Starknet, because the fee must be paid on L1 when the message is sent.

> **Important:** The sample payload below is illustrative. `starknet_estimateMessageFee` only succeeds when the message matches a real `l1_handler` flow on the target contract. Reusing the literal values here on mainnet returns `EXPECTED_FROM_BRIDGE_ONLY`, so replace them with a bridge-generated message from your integration before relying on the success example.

### How L1-to-L2 Messaging Works

1. An Ethereum contract calls the Starknet Core contract's `sendMessageToL2` function
2. The message includes the target L2 contract, entry point selector, and payload
3. The Starknet sequencer picks up the message and creates an `l1_handler` transaction
4. The L2 contract's handler function executes with the provided payload
5. The fee for L2 execution must be estimated and paid upfront on L1

## Request Parameters

- `message` (`object, required`): The L1 message to estimate
- `block_id` (`object | string, required`): Block context for the estimation

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_estimateMessageFee",
  "params": [
    {
      "from_address": "0xbe1259ff905cadbbaa62514388b71bdefb8aacc1",
      "to_address": "0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
      "entry_point_selector": "0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
      "payload": [
        "0x01234567890abcdef",
        "0x0de0b6b3a7640000",
        "0x0"
      ]
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `gas_consumed` (`FELT, required`): Amount of L2 gas consumed
- `gas_price` (`FELT, required`): Current L2 gas price
- `data_gas_consumed` (`FELT, required`): Amount of data gas (blob) consumed
- `data_gas_price` (`FELT, required`): Current data gas price
- `overall_fee` (`FELT, required`): Total estimated fee
- `unit` (`string, required`): Fee unit (`WEI` or `FRI`)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "gas_consumed": "<value>",
    "gas_price": "<value>",
    "data_gas_consumed": "<value>",
    "data_gas_price": "<value>",
    "overall_fee": "<value>",
    "unit": "<value>"
  }
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

### Error 5

## Illustrative Payload Error Example

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 40,
    "message": "Contract error",
    "data": {
      "revert_error": {
        "error": {
          "error": "0x45585045435445445f46524f4d5f4252494447455f4f4e4c59 ('EXPECTED_FROM_BRIDGE_ONLY')"
        }
      }
    }
  }
}
```

When you replace the illustrative payload with a real bridge-handler message, the method returns the standard fee object described in the table above. Keep the selector and payload aligned with the target contract's `l1_handler` ABI or Starknet rejects the estimate before execution.

## Errors

| Code | Message         | Description                                               |
| ---- | --------------- | --------------------------------------------------------- |
| 40   | Contract error  | The L2 contract execution failed during simulation        |
| 24   | Block not found | The specified block for estimation context does not exist |

## Examples

cURL
JavaScript
Python
Go

```bash
# Estimate fee for an L1-to-L2 message
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_estimateMessageFee",
    "params": [
      {
        "from_address": "0xbe1259ff905cadbbaa62514388b71bdefb8aacc1",
        "to_address": "0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
        "entry_point_selector": "0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
        "payload": [
          "0x01234567890abcdef",
          "0x0de0b6b3a7640000",
          "0x0"
        ]
      },
      "latest"
    ],
    "id": 1
  }'

# Parse the current error from the illustrative payload
curl -s -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_estimateMessageFee",
    "params": [
      {
        "from_address": "0xbe1259ff905cadbbaa62514388b71bdefb8aacc1",
        "to_address": "0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
        "entry_point_selector": "0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
        "payload": ["0x1"]
      },
      "latest"
    ],
    "id": 1
  }' | jq '{
    code: .error.code,
    message: .error.message,
    revert: .error.data.revert_error.error.error
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

// Estimate fee for an L1-to-L2 message
const message = {
  from_address: '0xbe1259ff905cadbbaa62514388b71bdefb8aacc1',
  to_address: '0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82',
  entry_point_selector: '0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5',
  payload: ['0x01234567890abcdef', '0x0de0b6b3a7640000', '0x0'],
};

try {
  const feeEstimate = await provider.estimateMessageFee(message, 'latest');
  console.log('Fee estimate:', feeEstimate);
} catch (error) {
  console.log('Contract error:', error.message);
  console.log('Use a bridge-generated handler message before relying on the fee estimate.');
}
```

```python
import requests

url = "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

message = {
    "from_address": "0xbe1259ff905cadbbaa62514388b71bdefb8aacc1",
    "to_address": "0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
    "entry_point_selector": "0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
    "payload": [
        "0x01234567890abcdef",
        "0x0de0b6b3a7640000",
        "0x0"
    ]
}

payload = {
    "jsonrpc": "2.0",
    "method": "starknet_estimateMessageFee",
    "params": [message, "latest"],
    "id": 1
}

response = requests.post(url, json=payload)
result = response.json()

if "error" in result:
    print(f"Error: {result['error']['message']}")
    revert = result["error"]["data"]["revert_error"]["error"]["error"]
    print(f"Revert detail: {revert}")
    print("Use a bridge-generated handler payload before expecting a fee object.")
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "math/big"
    "net/http"
)

type MessageFeeRequest struct {
    FromAddress        string   `json:"from_address"`
    ToAddress          string   `json:"to_address"`
    EntryPointSelector string   `json:"entry_point_selector"`
    Payload            []string `json:"payload"`
}

func main() {
    url := "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

    msg := MessageFeeRequest{
        FromAddress:        "0xbe1259ff905cadbbaa62514388b71bdefb8aacc1",
        ToAddress:          "0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
        EntryPointSelector: "0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
        Payload:            []string{"0x01234567890abcdef", "0x0de0b6b3a7640000", "0x0"},
    }

    body := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "starknet_estimateMessageFee",
        "params":  []interface{}{msg, "latest"},
        "id":      1,
    }

    jsonBody, _ := json.Marshal(body)
    resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    respBody, _ := io.ReadAll(resp.Body)

    var result map[string]interface{}
    json.Unmarshal(respBody, &result)

    if errObj, ok := result["error"].(map[string]interface{}); ok {
        fmt.Printf("Contract error: %v\n", errObj["message"])
        fmt.Println("Use a bridge-generated handler payload before expecting a fee object.")
        return
    }
}
```

## Use Cases

- **Bridge Operations** - Estimate the L2 processing fee before sending tokens from Ethereum to Starknet
- **Cross-Layer DeFi** - Calculate costs for L1-initiated actions on L2 protocols
- **Fee Budgeting** - Pre-calculate message fees with safety margins to avoid underpayment
- **User Interfaces** - Display estimated bridging costs to users before they confirm L1 transactions
- **Protocol Development** - Test and optimize `l1_handler` functions for gas efficiency

## Related Methods

- [starknet\_estimateFee](https://www.dwellir.com/docs/starknet/starknet_estimateFee) - Estimate fee for L2 transactions
- [starknet\_getMessagesStatus](https://www.dwellir.com/docs/starknet/starknet_getMessagesStatus) - Check L1-to-L2 message processing status
- [starknet\_getTransactionReceipt](https://www.dwellir.com/docs/starknet/starknet_getTransactionReceipt) - Get receipt for the resulting l1\_handler transaction
- [starknet\_call](https://www.dwellir.com/docs/starknet/starknet_call) - Read-only contract call for testing handler logic

---

## starknet_getBlockTransactionCount - Get Block Transaction Count

# starknet_getBlockTransactionCount - Get Block Transaction Count

Returns the number of transactions in a specific Starknet block. The block can be identified by hash, number, or the `"latest"` / `"pending"` tags.

## Overview

This method provides a lightweight way to query block activity without fetching full block data. It is commonly used in monitoring dashboards, indexing pipelines, and throughput analysis tools. Starknet processes batches of transactions into blocks that are then proven and submitted to Ethereum L1, so transaction count per block is a useful metric for understanding network load.

Starknet blocks can contain various transaction types including `INVOKE`, `DECLARE`, `DEPLOY_ACCOUNT`, and `L1_HANDLER` transactions. This method counts all transaction types in the block.

## Request Parameters

- `block_id` (`object | string, required`): Block identifier: `{"block_hash": "0x..."}`, `{"block_number": 123456}`, `"latest"`, or `"pending"`

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getBlockTransactionCount",
  "params": [
    {
      "block_number": 800000
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`integer, required`): Number of transactions in the block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 142
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

## Errors

| Code | Message         | Description                                       |
| ---- | --------------- | ------------------------------------------------- |
| 24   | Block not found | The specified block hash or number does not exist |

## Examples

cURL
JavaScript
Python
Go

```bash
# Get transaction count for a specific block number
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getBlockTransactionCount",
    "params": [{"block_number": 800000}],
    "id": 1
  }'

# Get transaction count for the latest block
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getBlockTransactionCount",
    "params": ["latest"],
    "id": 1
  }'

# Get transaction count by block hash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getBlockTransactionCount",
    "params": [
      {"block_hash": "0x07d328a71faf48c5c3857e99f20a77b18522480956d1cd5bff1ff2df3c8b427b"}
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

// Get transaction count for the latest block
const latestCount = await provider.getBlockTransactionCount('latest');
console.log('Latest block tx count:', latestCount);

// Get transaction count by block number
const count = await provider.getBlockTransactionCount(800000);
console.log('Block 800000 tx count:', count);

// Monitor throughput over recent blocks
async function measureThroughput(blockCount = 10) {
  const latestBlock = await provider.getBlockNumber();
  let totalTx = 0;

  for (let i = 0; i < blockCount; i++) {
    const blockNum = latestBlock - i;
    const txCount = await provider.getBlockTransactionCount(blockNum);
    totalTx += txCount;
    console.log(`Block ${blockNum}: ${txCount} transactions`);
  }

  const avgTxPerBlock = totalTx / blockCount;
  console.log(`\nAverage transactions per block: ${avgTxPerBlock.toFixed(1)}`);
  console.log(`Total transactions in last ${blockCount} blocks: ${totalTx}`);
}

await measureThroughput();
```

```python
import requests

url = "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

# Get latest block transaction count
payload = {
    "jsonrpc": "2.0",
    "method": "starknet_getBlockTransactionCount",
    "params": ["latest"],
    "id": 1
}

response = requests.post(url, json=payload)
tx_count = response.json()["result"]
print(f"Latest block transaction count: {tx_count}")

# Get transaction count by block number
payload["params"] = [{"block_number": 800000}]
response = requests.post(url, json=payload)
tx_count = response.json()["result"]
print(f"Block 800000 transaction count: {tx_count}")

# Throughput analysis over a range of blocks
def analyze_throughput(start_block: int, end_block: int):
    """Analyze transaction throughput across a block range."""
    counts = []

    for block_num in range(start_block, end_block + 1):
        resp = requests.post(url, json={
            "jsonrpc": "2.0",
            "method": "starknet_getBlockTransactionCount",
            "params": [{"block_number": block_num}],
            "id": 1,
        })
        count = resp.json()["result"]
        counts.append(count)

    total = sum(counts)
    avg = total / len(counts) if counts else 0
    peak = max(counts) if counts else 0

    print(f"\nThroughput Analysis (blocks {start_block}-{end_block}):")
    print(f"  Total transactions: {total}")
    print(f"  Average per block: {avg:.1f}")
    print(f"  Peak block: {peak}")
    print(f"  Empty blocks: {counts.count(0)}")

    return counts

analyze_throughput(800000, 800010)
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func getBlockTxCount(url string, blockNum int) (int, error) {
    body := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "starknet_getBlockTransactionCount",
        "params":  []interface{}{map[string]int{"block_number": blockNum}},
        "id":      1,
    }

    jsonBody, _ := json.Marshal(body)
    resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return 0, err
    }
    defer resp.Body.Close()

    respBody, _ := io.ReadAll(resp.Body)

    var result map[string]interface{}
    json.Unmarshal(respBody, &result)

    count := int(result["result"].(float64))
    return count, nil
}

func main() {
    url := "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

    count, err := getBlockTxCount(url, 800000)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Block 800000 transaction count: %d\n", count)

    // Analyse recent blocks
    fmt.Println("\nRecent block activity:")
    for i := 800000; i <= 800005; i++ {
        c, _ := getBlockTxCount(url, i)
        fmt.Printf("  Block %d: %d transactions\n", i, c)
    }
}
```

## Use Cases

- **Throughput Monitoring** - Track Starknet network activity and transaction volume over time
- **Block Explorer** - Display transaction counts in block list views without fetching full block data
- **Indexing Pipelines** - Pre-allocate resources or decide batch sizes based on block transaction counts
- **Network Health** - Detect anomalous blocks (empty or unusually large) for alerting
- **Analytics Dashboards** - Calculate average transactions per block for network performance metrics

## Related Methods

- [starknet\_getBlockWithTxs](https://www.dwellir.com/docs/starknet/starknet_getBlockWithTxs) - Get block with full transaction objects
- [starknet\_getBlockWithTxHashes](https://www.dwellir.com/docs/starknet/starknet_getBlockWithTxHashes) - Get block with transaction hashes only
- [starknet\_blockNumber](https://www.dwellir.com/docs/starknet/starknet_blockNumber) - Get the latest block number
- [starknet\_getBlockWithReceipts](https://www.dwellir.com/docs/starknet/starknet_getBlockWithReceipts) - Get block with transaction receipts
- [starknet\_blockHashAndNumber](https://www.dwellir.com/docs/starknet/starknet_blockHashAndNumber) - Get latest block hash and number

---

## starknet_getBlockWithReceipts - Get block I...

# starknet_getBlockWithReceipts - Get block I...

Get block information with full transactions and receipts given the block id

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getBlockWithReceipts",
  "params": [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The resulting block information with full transactions Block information with full transactions and receipts

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message         |
| ---- | --------------- |
| 24   | Block not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getBlockWithReceipts",
    "params": [
      {
        "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
      }
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getBlockWithReceipts',
  params: [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getBlockWithTxHashes - Get block I...

# starknet_getBlockWithTxHashes - Get block I...

Get block information with transaction hashes given the block id

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getBlockWithTxHashes",
  "params": [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The resulting block information with transaction hashes Block information with transaction hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message         |
| ---- | --------------- |
| 24   | Block not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getBlockWithTxHashes",
    "params": [
      {
        "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
      }
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getBlockWithTxHashes',
  params: [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getBlockWithTxs - Get block Info w...

# starknet_getBlockWithTxs - Get block Info w...

Get block information with full transactions given the block id

## Request Parameters

- `block_id` (`string, required`): Block reference: `"latest"`, `"l1_accepted"`, block hash, or block number

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getBlockWithTxs",
  "params": [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The resulting block information with full transactions Block information with full transaction objects

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message         |
| ---- | --------------- |
| 24   | Block not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getBlockWithTxs",
    "params": [
      {
        "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
      }
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getBlockWithTxs',
  params: [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getClass - Get the contract class...

# starknet_getClass - Get the contract class...

Get the contract class definition in the given block associated with the given hash

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)
- `class_hash` (`felt252, required`): Class hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getClass",
  "params": [
    "latest",
    "0x7f3777c99f3700505ea966676aac4a0d692c2a9f5e667f4c606b51ca1dd3420"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The contract class, if found Contract class definition with Sierra program, entry points, and ABI

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message              |
| ---- | -------------------- |
| 24   | Block not found      |
| 28   | Class hash not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getClass",
    "params": [
      "latest",
      "0x7f3777c99f3700505ea966676aac4a0d692c2a9f5e667f4c606b51ca1dd3420"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getClass',
  params: [
    "latest",
    "0x7f3777c99f3700505ea966676aac4a0d692c2a9f5e667f4c606b51ca1dd3420"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getClassAt - Get the contract clas...

# starknet_getClassAt - Get the contract clas...

Get the contract class definition in the given block at the given address

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)
- `contract_address` (`felt252, required`): Contract address

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getClassAt",
  "params": [
    "latest",
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The contract class Contract class definition with Sierra program, entry points, and ABI

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message            |
| ---- | ------------------ |
| 24   | Block not found    |
| 20   | Contract not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getClassAt",
    "params": [
      "latest",
      "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getClassAt',
  params: [
    "latest",
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getClassHashAt - Get the contract...

# starknet_getClassHashAt - Get the contract...

Get the contract class hash in the given block for the contract deployed at the given address

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)
- `contract_address` (`felt252, required`): Contract address

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getClassHashAt",
  "params": [
    "latest",
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The class hash of the given contract Class hash (felt252)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message            |
| ---- | ------------------ |
| 24   | Block not found    |
| 20   | Contract not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getClassHashAt",
    "params": [
      "latest",
      "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getClassHashAt',
  params: [
    "latest",
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getEvents - Returns all events mat...

# starknet_getEvents - Returns all events mat...

Returns all events matching the given filter

Returns all event objects matching the conditions in the provided filter

## Request Parameters

- `filter` (`object, required`): Event filter with `from_block`, `to_block`, `address`, `keys`, and `chunk_size`

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getEvents",
  "params": [
    {
      "chunk_size": 1,
      "from_block": "latest",
      "to_block": "latest",
      "address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
      "keys": [
        [
          "0x1"
        ]
      ]
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): All the event objects matching the filter Events chunk with matching events and continuation token

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message                                               |
| ---- | ----------------------------------------------------- |
| 31   | Requested page size is too big                        |
| 33   | The supplied continuation token is invalid or unknown |
| 24   | Block not found                                       |
| 34   | Too many keys provided in a filter                    |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getEvents",
    "params": [
      {
        "chunk_size": 1,
        "from_block": "latest",
        "to_block": "latest",
        "address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "keys": [
          [
            "0x1"
          ]
        ]
      }
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getEvents',
  params: [
    {
      chunk_size: 1,
      from_block: 'latest',
      to_block: 'latest',
      address: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
      keys: [['0x1']],
    },
  ],
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getMessagesStatus - Given an l1 tx...

# starknet_getMessagesStatus - Given an l1 tx...

Given an l1 tx hash, returns the associated l1\_handler tx hashes and statuses for all L1 -> L2 messages sent by the l1 transaction, ordered by the l1 tx sending order

## Request Parameters

- `transaction_hash` (`string, required`): L1 transaction hash (hex string)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getMessagesStatus",
  "params": [
    "0x01438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Successful response payload. Array of message status objects with transaction hash, finality status, and execution status

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message                    |
| ---- | -------------------------- |
| 29   | Transaction hash not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getMessagesStatus",
    "params": [
      "0x01438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getMessagesStatus',
  params: [
    "0x01438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getNonce - Get the nonce associate...

# starknet_getNonce - Get the nonce associate...

Get the nonce associated with the given address in the given block

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)
- `contract_address` (`felt252, required`): Contract address

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getNonce",
  "params": [
    "latest",
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The contract's nonce at the requested state Contract nonce (felt252)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message            |
| ---- | ------------------ |
| 24   | Block not found    |
| 20   | Contract not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getNonce",
    "params": [
      "latest",
      "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getNonce',
  params: [
    "latest",
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getStateUpdate - Get the Info abou...

# starknet_getStateUpdate - Get the Info abou...

Get the information about the result of executing the requested block

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getStateUpdate",
  "params": [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The information about the state update of the requested block State update with block hash, old root, new root, and state diff

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message         |
| ---- | --------------- |
| 24   | Block not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getStateUpdate",
    "params": [
      {
        "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
      }
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getStateUpdate',
  params: [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    }
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getStorageAt - Get the value of th...

# starknet_getStorageAt - Get the value of th...

Get the value of the storage at the given address and key

## Request Parameters

- `contract_address` (`felt252, required`): Contract address
- `key` (`felt252, required`): Storage key
- `block_id` (`string, required`): Block reference: `"latest"`, `"l1_accepted"`, block hash, or block number

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getStorageAt",
  "params": [
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
    "0x0",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The value at the given key for the given contract. 0 if no value is found Storage value (felt252)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message            |
| ---- | ------------------ |
| 20   | Contract not found |
| 24   | Block not found    |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getStorageAt",
    "params": [
      "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getStorageAt',
  params: [
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
    "0x0",
    "latest"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getStorageProof - Get merkle paths...

# starknet_getStorageProof - Get merkle paths...

Get merkle paths in one of the state tries: global state, classes, individual contract. A single request can query for any mix of the three types of storage proofs (classes, contracts, and storage).

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)
- `class_hashes` (`felt252[], required`): Array of class hashes (optional)
- `contract_addresses` (`felt252[], required`): Array of contract addresses (optional)
- `contracts_storage_keys` (`array, required`): Array of contract-storage key pairs (optional)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getStorageProof",
  "params": [
    "latest",
    [],
    [
      "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
    ],
    [
      {
        "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "storage_keys": [
          "0x0"
        ]
      }
    ]
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The requested storage proofs. Note that if a requested leaf has the default value, the path to it may end in an edge node whose path is not a prefix of the requested leaf, thus effectively proving non-membership Storage proof object with classes proof, contracts proof, storage proofs, and global roots

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message                                                                         |
| ---- | ------------------------------------------------------------------------------- |
| 24   | Block not found                                                                 |
| 42   | the node doesn't support storage proofs for blocks that are too far in the past |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getStorageProof",
    "params": [
      "latest",
      [],
      [
        "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
      ],
      [
        {
          "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
          "storage_keys": [
            "0x0"
          ]
        }
      ]
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getStorageProof',
  params: [
    "latest",
    [],
    [
      "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
    ],
    [
      {
        "contract_address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        "storage_keys": [
          "0x0"
        ]
      }
    ]
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getTransactionByBlockIdAndIndex - ...

# starknet_getTransactionByBlockIdAndIndex - ...

Get the details of a transaction by a given block id and index

Get the details of the transaction given by the identified block and index in that block. If no transaction is found, null is returned.

## Request Parameters

- `block_id` (`string, required`): Block reference ("latest", "l1_accepted", block hash, or block number)
- `index` (`integer, required`): Transaction index in the block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getTransactionByBlockIdAndIndex",
  "params": [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    },
    0
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Transaction details at the specified index

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message                              |
| ---- | ------------------------------------ |
| 24   | Block not found                      |
| 27   | Invalid transaction index in a block |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getTransactionByBlockIdAndIndex",
    "params": [
      {
        "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
      },
      0
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getTransactionByBlockIdAndIndex',
  params: [
    {
      "block_hash": "0x15d2401c3a65e0a2b74b20402b01bbea28b118291b07cdca4a94fe4e964270a"
    },
    0
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getTransactionByHash - Get the det...

# starknet_getTransactionByHash - Get the det...

Get the details and status of a submitted transaction

## Request Parameters

- `transaction_hash` (`felt252, required`): Transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getTransactionByHash",
  "params": [
    "0x27f867e8c63aeb7e85a756c67191a26d9c2c71fb4490b4cce4677ff273659bf"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Successful response payload.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message                    |
| ---- | -------------------------- |
| 29   | Transaction hash not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getTransactionByHash",
    "params": [
      "0x27f867e8c63aeb7e85a756c67191a26d9c2c71fb4490b4cce4677ff273659bf"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getTransactionByHash',
  params: [
    "0x27f867e8c63aeb7e85a756c67191a26d9c2c71fb4490b4cce4677ff273659bf"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_getTransactionReceipt - Get Transaction Receipt

# starknet_getTransactionReceipt - Get Transaction Receipt

Returns the receipt of a transaction identified by its hash. The receipt includes execution status, actual fee paid, emitted events, and block inclusion details. This is the primary method for confirming whether a transaction succeeded or reverted.

## Overview

After a transaction is submitted to Starknet, it goes through several stages: `RECEIVED`, `ACCEPTED_ON_L2`, and finally `ACCEPTED_ON_L1` (once the proof is verified on Ethereum). The transaction receipt reflects the current status and provides detailed execution results.

Starknet transaction receipts differ from EVM receipts in several ways:

- Fees are denominated in **STRK** or **ETH** (depending on the fee token used)
- Events use **felt252** keys and data values (Cairo's native field element type)
- Execution status distinguishes between `SUCCEEDED` and `REVERTED`
- L2-to-L1 messages emitted during execution are tracked in `messages_sent`
- `execution_resources` reports fee-relevant buckets such as `l1_gas`, `l2_gas`, and `l1_data_gas`

## Request Parameters

- `transaction_hash` (`FELT, required`): The hash of the transaction

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getTransactionReceipt",
  "params": [
    "0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Transaction type: `INVOKE`, `DECLARE`, `DEPLOY_ACCOUNT`, or `L1_HANDLER`
- `transaction_hash` (`FELT, required`): Hash of the transaction
- `actual_fee` (`object, required`): `{amount, unit}` -- actual fee paid
- `execution_status` (`string, required`): SUCCEEDED` or `REVERTED
- `finality_status` (`string, required`): ACCEPTED_ON_L2` or `ACCEPTED_ON_L1
- `block_hash` (`FELT, required`): Hash of the block containing the transaction
- `block_number` (`integer, required`): Block number
- `messages_sent` (`array, required`): L2-to-L1 messages sent during execution
- `events` (`array, required`): Events emitted during execution
- `execution_resources` (`object, required`): Computation resources consumed, including `l1_gas`, `l2_gas`, and `l1_data_gas`
- `revert_reason` (`string, required`): Revert message if `execution_status` is `REVERTED`

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "INVOKE",
    "transaction_hash": "0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4",
    "actual_fee": {
      "amount": "0x86db1e659445f40",
      "unit": "FRI"
    },
    "execution_status": "SUCCEEDED",
    "finality_status": "ACCEPTED_ON_L2",
    "block_hash": "0x18a25f86e52b08b83f66b578ee41951710d08f3b058f56ab07a6a84136cb3f3",
    "block_number": 7790506,
    "messages_sent": [],
    "events": [
      {
        "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
        "keys": [
          "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"
        ],
        "data": [
          "0x6ed5b415ead1c0e03fb2d38bce798d5275fc22dfebafc41e7b748c051653db0",
          "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8",
          "0x86db1e659445f40",
          "0x0"
        ]
      }
    ],
    "execution_resources": {
      "l1_gas": 0,
      "l2_gas": 23909440,
      "l1_data_gas": 384
    }
  }
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

### Error 4

## Errors

| Code | Message                    | Description                                                  |
| ---- | -------------------------- | ------------------------------------------------------------ |
| 29   | Transaction hash not found | The transaction does not exist or has not been processed yet |

## Examples

cURL
JavaScript
Python
Go

```bash
# Get transaction receipt
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getTransactionReceipt",
    "params": [
      "0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"
    ],
    "id": 1
  }'

# Check execution status with jq
curl -s -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getTransactionReceipt",
    "params": [
      "0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"
    ],
    "id": 1
  }' | jq '{
    status: .result.execution_status,
    finality: .result.finality_status,
    fee: .result.actual_fee,
    events_count: (.result.events | length)
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const txHash = '0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4';

// Get transaction receipt
const receipt = await provider.getTransactionReceipt(txHash);

console.log('Status:', receipt.execution_status);
console.log('Finality:', receipt.finality_status);
console.log('Fee:', receipt.actual_fee);
console.log('Events:', receipt.events.length);

if (receipt.execution_status === 'REVERTED') {
  console.log('Revert reason:', receipt.revert_reason);
}

// Wait for a transaction to be accepted on L2
async function waitForAcceptance(txHash, pollIntervalMs = 5000) {
  while (true) {
    try {
      const receipt = await provider.getTransactionReceipt(txHash);

      if (receipt.finality_status === 'ACCEPTED_ON_L2' ||
          receipt.finality_status === 'ACCEPTED_ON_L1') {
        return receipt;
      }
    } catch (error) {
      // Transaction not yet processed, keep polling
    }

    await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
  }
}

// Parse transfer events from receipt
function parseTransferEvents(receipt, tokenAddress) {
  const TRANSFER_KEY = '0x0099cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9';

  return receipt.events
    .filter(e => e.from_address === tokenAddress && e.keys[0] === TRANSFER_KEY)
    .map(e => ({
      from: e.data[0],
      to: e.data[1],
      amount: BigInt(e.data[2]),
    }));
}
```

```python
import requests
import time

url = "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"

tx_hash = "0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"

payload = {
    "jsonrpc": "2.0",
    "method": "starknet_getTransactionReceipt",
    "params": [tx_hash],
    "id": 1
}

response = requests.post(url, json=payload)
receipt = response.json().get("result")

if receipt:
    print(f"Status: {receipt['execution_status']}")
    print(f"Finality: {receipt['finality_status']}")
    print(f"Fee: {receipt['actual_fee']}")
    print(f"Block: {receipt.get('block_number')}")
    print(f"Events emitted: {len(receipt.get('events', []))}")

    if receipt["execution_status"] == "REVERTED":
        print(f"Revert reason: {receipt.get('revert_reason', 'Unknown')}")
else:
    print("Transaction not found")

# Wait for transaction confirmation
def wait_for_receipt(tx_hash: str, timeout_seconds: int = 300, poll_interval: int = 5):
    """Wait for a Starknet transaction receipt with timeout."""
    start = time.time()

    while time.time() - start < timeout_seconds:
        resp = requests.post(url, json={
            "jsonrpc": "2.0",
            "method": "starknet_getTransactionReceipt",
            "params": [tx_hash],
            "id": 1,
        })

        result = resp.json()

        if "result" in result:
            receipt = result["result"]
            status = receipt.get("finality_status", "")

            if status in ("ACCEPTED_ON_L2", "ACCEPTED_ON_L1"):
                return receipt

        time.sleep(poll_interval)

    raise TimeoutError(f"Transaction {tx_hash} not confirmed within {timeout_seconds}s")

# Parse events from a receipt
def parse_events(receipt: dict, contract_address: str = None):
    """Extract and decode events from a transaction receipt."""
    events = receipt.get("events", [])

    if contract_address:
        events = [e for e in events if e["from_address"] == contract_address]

    return [
        {
            "contract": e["from_address"],
            "keys": e["keys"],
            "data": e["data"],
        }
        for e in events
    ]
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type Fee struct {
    Amount string `json:"amount"`
    Unit   string `json:"unit"`
}

type Event struct {
    FromAddress string   `json:"from_address"`
    Keys        []string `json:"keys"`
    Data        []string `json:"data"`
}

type Receipt struct {
    Type            string  `json:"type"`
    TxHash          string  `json:"transaction_hash"`
    ActualFee       Fee     `json:"actual_fee"`
    ExecutionStatus string  `json:"execution_status"`
    FinalityStatus  string  `json:"finality_status"`
    BlockNumber     int     `json:"block_number"`
    Events          []Event `json:"events"`
    RevertReason    string  `json:"revert_reason"`
}

func main() {
    url := "https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY"
    txHash := "0x1438e2dc065c46840a28564c4c0a0db0bd43a9f54554cad7992f512b3f29ec4"

    body := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "starknet_getTransactionReceipt",
        "params":  []interface{}{txHash},
        "id":      1,
    }

    jsonBody, _ := json.Marshal(body)
    resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    respBody, _ := io.ReadAll(resp.Body)

    var result struct {
        Result Receipt `json:"result"`
    }
    json.Unmarshal(respBody, &result)

    r := result.Result
    fmt.Printf("Status: %s\n", r.ExecutionStatus)
    fmt.Printf("Finality: %s\n", r.FinalityStatus)
    fmt.Printf("Fee: %s %s\n", r.ActualFee.Amount, r.ActualFee.Unit)
    fmt.Printf("Block: %d\n", r.BlockNumber)
    fmt.Printf("Events: %d\n", len(r.Events))
}
```

## Use Cases

- **Transaction Confirmation** - Verify that a submitted transaction was executed successfully
- **Fee Tracking** - Record actual fees paid for cost analysis and accounting
- **Event Monitoring** - Extract emitted events for token transfers, contract state changes, and DeFi activity
- **Error Debugging** - Inspect revert reasons for failed transactions
- **L1 Finality Tracking** - Monitor when transactions achieve `ACCEPTED_ON_L1` finality via Ethereum proof verification
- **Payment Verification** - Confirm token transfer completion for payment processing systems

## Related Methods

- [starknet\_getTransactionByHash](https://www.dwellir.com/docs/starknet/starknet_getTransactionByHash) - Get transaction details (without execution results)
- [starknet\_getTransactionStatus](https://www.dwellir.com/docs/starknet/starknet_getTransactionStatus) - Get lightweight finality status
- [starknet\_getEvents](https://www.dwellir.com/docs/starknet/starknet_getEvents) - Query events by filter across blocks
- [starknet\_getBlockWithReceipts](https://www.dwellir.com/docs/starknet/starknet_getBlockWithReceipts) - Get all receipts in a block

---

## starknet_getTransactionStatus - Gets the tr...

# starknet_getTransactionStatus - Gets the tr...

Gets the transaction status (possibly reflecting that the tx is still in the mempool, or dropped from it)

## Request Parameters

- `transaction_hash` (`felt252, required`): Transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_getTransactionStatus",
  "params": [
    "0x27f867e8c63aeb7e85a756c67191a26d9c2c71fb4490b4cce4677ff273659bf"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Successful response payload. Transaction status with finality status, execution status, and failure reason (if any)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Errors

| Code | Message                    |
| ---- | -------------------------- |
| 29   | Transaction hash not found |

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_getTransactionStatus",
    "params": [
      "0x27f867e8c63aeb7e85a756c67191a26d9c2c71fb4490b4cce4677ff273659bf"
    ],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_getTransactionStatus',
  params: [
    "0x27f867e8c63aeb7e85a756c67191a26d9c2c71fb4490b4cce4677ff273659bf"
  ]
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_specVersion - Returns the version...

# starknet_specVersion - Returns the version...

Returns the version of the Starknet JSON-RPC specification being used

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_specVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): Semver of Starknet's JSON-RPC spec being used JSON-RPC specification version (string)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_specVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_specVersion',
  params: []
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## starknet_syncing - Returns an object about...

# starknet_syncing - Returns an object about...

Returns an object about the sync status, or false if the node is not synching

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "starknet_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`OBJECT, required`): The status of the node, if it is currently synchronizing state. FALSE otherwise Sync status object or false if not syncing

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Examples

cURL
JavaScript

```bash
curl -X POST https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "starknet_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { RpcProvider } from 'starknet';

const provider = new RpcProvider({
  nodeUrl: 'https://api-starknet-mainnet.n.dwellir.com/YOUR_API_KEY',
});

const payload = {
  method: 'starknet_syncing',
  params: []
};

const result = await provider.fetchEndpoint(payload.method, payload.params);
console.log(result);
```

---

## Sui Blockchain gRPC API Documentation

# Sui Blockchain gRPC API Documentation

## Sui RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Sui supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Connect to Sui mainnet

Dwellir provides Sui full-node access through the network's gRPC API. Sui removed JSON-RPC from full nodes in `mainnet-v1.82.3`. Existing JSON-RPC integrations must [migrate to gRPC or GraphQL](https://www.dwellir.com/docs/sui/json-rpc-removal).

Connect over TLS on port 443:

```text
api-sui-mainnet-full.n.dwellir.com:443
```

Send your API key in the `x-api-key` metadata header. Do not append it to the endpoint path.

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetServiceInfo
```

Get an API key from the [Dwellir dashboard](https://dashboard.dwellir.com). Testnet access is available through dedicated node clusters.

## API Reference

The reference covers 28 methods across seven stable `sui.rpc.v2` services and the experimental `sui.rpc.v2alpha.ProofService`:

- [Ledger Service](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info) for checkpoints, epochs, transactions, events, and objects
- [State Service](https://www.dwellir.com/docs/sui/grpc/state/get-balance) for balances, owned objects, dynamic fields, and coin information
- [Transaction Execution Service](https://www.dwellir.com/docs/sui/grpc/transaction/execute) for execution and simulation
- [Move Package Service](https://www.dwellir.com/docs/sui/grpc/package/get-package) for packages, modules, functions, types, and versions
- [Subscription Service](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) for checkpoint, transaction, and event streams
- [Signature Verification Service](https://www.dwellir.com/docs/sui/grpc/signature/verify) for off-chain signature verification
- [Name Service](https://www.dwellir.com/docs/sui/grpc/name/lookup-name) for forward and reverse SuiNS lookup
- [Proof Service](https://www.dwellir.com/docs/sui/grpc/proof/get-checkpoint-object-proof) for experimental checkpoint object proofs

[View all gRPC methods](https://www.dwellir.com/docs/sui#api-reference)

## Choose the right API

Use gRPC for typed full-node queries, transaction submission, and live streams. Use Sui GraphQL when you need flexible joins, advanced filtering, or historical data beyond the node's retention window.

## Client setup

- [grpcurl](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)
- [TypeScript](https://www.dwellir.com/docs/sui/grpc-setup-typescript)
- [Python](https://www.dwellir.com/docs/sui/grpc-setup-python)
- [Go](https://www.dwellir.com/docs/sui/grpc-setup-go)
- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)

## Support

For help with an integration or a dedicated Sui cluster, contact <support@dwellir.com>.

### Related reading

- [Best Sui RPC Providers 2026](https://www.dwellir.com/blog/best-sui-rpc-providers)

---

## Sui gRPC API - High Performance Access

# Sui gRPC API - High Performance Access

## High-Performance Blockchain Data Access

Dwellir's Sui gRPC API provides typed full-node access for querying data, executing transactions, and consuming live streams. Sui removed JSON-RPC from full nodes in `mainnet-v1.82.3`, so existing integrations must [migrate to gRPC or GraphQL](https://www.dwellir.com/docs/sui/json-rpc-removal). Built on Protocol Buffers and HTTP/2, gRPC offers efficient binary serialization and explicit request and response schemas.

**Endpoint:** connect over TLS on port 443:

```
api-sui-mainnet-full.n.dwellir.com:443
```

> Port 443 is typically not required because most gRPC libraries default to it for TLS connections. Tools such as `grpcurl` require it explicitly.

**Authentication:** pass your API key as gRPC metadata, not as a URL path segment:

```
x-api-key: YOUR_API_TOKEN
```

Get your API token from [dashboard.dwellir.com](https://dashboard.dwellir.com). See [Connection Configuration](#connection-configuration) and [Authentication](#authentication) for full details, or jump straight to [language-specific setup guides](#language-specific-setup).

## Why Use gRPC?

### Performance Advantages

- **Binary Protocol**: Protocol Buffers provide compact binary encoding
- **HTTP/2 Multiplexing**: Multiple concurrent requests over a single connection eliminate connection overhead
- **Streaming Support**: Server-streaming subscriptions deliver checkpoints, transactions, and events without polling
- **Efficient Serialization**: Native binary format significantly reduces parsing overhead

### Developer Benefits

- **Strong Typing**: Protocol Buffer definitions provide compile-time type checking
- **Code Generation**: Automatic client generation from `.proto` files eliminates boilerplate
- **Language Support**: Native implementations available for Go, Python, TypeScript, Rust, and more
- **Built-in Features**: Deadlines, cancellation, and load balancing come standard

### Use Cases for gRPC

- **High-frequency trading**: Microsecond-level latency requirements
- **Real-time monitoring**: Live checkpoint, transaction, and event processing
- **Analytics pipelines**: Bulk data extraction and processing
- **Mobile applications**: Reduced bandwidth consumption on limited connections
- **Microservices**: Efficient inter-service communication in distributed architectures

## gRPC and the retired JSON-RPC API

| Feature            | gRPC                                                              | Retired JSON-RPC                   |
| ------------------ | ----------------------------------------------------------------- | ---------------------------------- |
| **Protocol**       | HTTP/2 + Protocol Buffers                                         | HTTP/1.1 + JSON                    |
| **Payload Format** | Compact Protocol Buffers                                          | Text-based JSON                    |
| **Streaming**      | Server-streaming checkpoint, transaction, and event subscriptions | Removed from Sui full nodes        |
| **Type Safety**    | Strong typing via `.proto`                                        | Runtime validation required        |
| **Serialization**  | Generated binary codecs                                           | Runtime JSON parsing               |
| **Availability**   | Supported full-node API                                           | Removed in `mainnet-v1.82.3`       |
| **Tooling**        | Generated clients or reflection-aware tools                       | Existing clients require migration |

## Available Services

The API exposes 27 methods across seven stable `sui.rpc.v2` services. One experimental `sui.rpc.v2alpha` proof method brings the total to 28.

### 1. Ledger Service

Access historical blockchain data and core object information:

- Retrieve objects by ID with field masking
- Query transactions with execution details
- Access checkpoint and epoch data
- Batch operations for multiple objects or transactions

### 2. State Service

Query current blockchain state efficiently:

- Check account balances for any coin type
- List owned objects with pagination
- Enumerate dynamic fields
- Retrieve coin metadata and information

### 3. Transaction Execution Service

Execute and broadcast transactions:

- Submit signed transactions for on-chain execution
- Simulate transactions before execution for gas estimation and validation

### 4. Move Package Service

Inspect Move smart contracts and modules:

- Retrieve package information and metadata
- Query function signatures and capabilities
- Inspect data types and structures
- List package version history

### 5. Subscription Service

Real-time streaming:

- Subscribe to checkpoint updates as they finalize
- Subscribe to transactions with server-side filters
- Subscribe to events with server-side filters
- Request only the response fields needed with a field mask

### 6. Signature Verification Service

Cryptographic signature operations:

- Verify transaction signatures off-chain
- Validate multi-sig configurations
- Check signature authenticity

### 7. Name Service

Resolve SuiNS records:

- Resolve a SuiNS name to its record
- Reverse-resolve an address to its default name

### Experimental Proof Service

Request a checkpoint object proof from `sui.rpc.v2alpha.ProofService`. The alpha namespace can change without the compatibility guarantees of the stable v2 services.

## Connection Configuration

### Endpoint Structure

Dwellir's Sui gRPC endpoints follow this format:

```
api-sui-mainnet-full.n.dwellir.com:443
```

**Important Notes:**

- gRPC uses port **443**
- Connections require TLS encryption
- Authentication via metadata headers

### Network Endpoints

| Network     | gRPC Endpoint                             |
| ----------- | ----------------------------------------- |
| **Mainnet** | `api-sui-mainnet-full.n.dwellir.com:443`  |
| **Testnet** | Dedicated node clusters only (contact us) |

> **Note:** Testnet access is currently offered only through dedicated node clusters. Reach out to our team to provision a testnet endpoint.

## Authentication

All gRPC requests to Dwellir's Sui endpoints require sending your API token in the `x-api-key` metadata header:

```
x-api-key: YOUR_API_TOKEN
```

Do **not** append the token as a path segment to the gRPC endpoint.
Retrieve your API token from the [Dwellir dashboard](https://dashboard.dwellir.com) and pass it only via the header.

TypeScript
Python
Go

```typescript
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);

client.GetObject(request, metadata, (error, response) => { ... });
```

```python
metadata = [('x-api-key', API_TOKEN)]
response = client.GetObject(request, metadata=metadata)
```

```go
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
resp, err := client.GetServiceInfo(ctx, &pb.GetServiceInfoRequest{})
```

### Security Best Practices

- **Never expose tokens in client-side code**: Use backend services to proxy gRPC requests
- **Rotate tokens periodically**: Generate new tokens through the Dwellir dashboard
- **Use environment variables**: Store tokens outside of source code
- **Monitor usage**: Track API consumption via the Dwellir dashboard

## Quick Start Guide

### Prerequisites

1. **Dwellir API Key**: Obtain from [dashboard.dwellir.com](https://dashboard.dwellir.com)
2. **Protocol Buffers**: Install `protoc` compiler for code generation
3. **gRPC Libraries**: Language-specific gRPC implementation

### Protocol Buffer Files

Download the official Sui proto definitions from the [MystenLabs sui-apis repository](https://github.com/MystenLabs/sui-apis):

```bash
# Clone the Sui API definitions
git clone https://github.com/MystenLabs/sui-apis.git
cd sui-apis
```

Key proto files:

- `ledger_service.proto` - Ledger service definitions
- `state_service.proto` - Current state queries
- `transaction_execution_service.proto` - Transaction execution and simulation
- `move_package_service.proto` - Move package inspection
- `subscription_service.proto` - Checkpoint, transaction, and event subscriptions
- `signature_verification_service.proto` - Signature operations
- `name_service.proto` - SuiNS resolution

### Language-Specific Setup

TypeScript
Python
Go

```bash
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client

# Initialize Node.js project
npm init -y

# Install dependencies
npm install @grpc/grpc-js @grpc/proto-loader
npm install -D @types/node tsx

# Download proto files
mkdir -p protos
# Copy proto files from sui-apis repository to protos/
```

**Basic Client Example:**

```typescript
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

// Configuration
const ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com:443';
const API_TOKEN = 'your_api_token_here';

// Load proto definition
const packageDefinition = protoLoader.loadSync(
  './protos/sui/rpc/v2/ledger_service.proto',
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: ['./protos']
  }
);

const protoDescriptor = grpc.loadPackageDefinition(packageDefinition) as any;

// Create secure channel with TLS
const credentials = grpc.credentials.createSsl();

// Setup authentication metadata
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);

// Create client
const client = new protoDescriptor.sui.rpc.v2.LedgerService(
  ENDPOINT,
  credentials
);

// Example: Get object information
const objectId = '0x5';

const request = {
  object_id: objectId,
  read_mask: {
    paths: ['object_id', 'version', 'digest', 'owner', 'object_type']
  }
};

client.GetObject(request, metadata, (error, response) => {
  if (error) {
    console.error('Error:', error.message);
    return;
  }

  console.log('Object data:', JSON.stringify(response, null, 2));
});
```

```bash
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install grpcio grpcio-tools protobuf googleapis-common-protos

# Create protos directory
mkdir protos
# Copy proto files from sui-apis repository to protos/

# Generate Python code from proto files
python -m grpc_tools.protoc \
  --proto_path=./protos \
  --python_out=. \
  --grpc_python_out=. \
  ./protos/sui/rpc/v2/*.proto
```

**Basic Client Example:**

```python
import grpc
from google.protobuf import field_mask_pb2
from sui.rpc.v2 import ledger_service_pb2, ledger_service_pb2_grpc

# Configuration
ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com:443'
API_TOKEN = 'your_api_token_here'

# Create secure channel with TLS
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(ENDPOINT, credentials)

# Create client stub
client = ledger_service_pb2_grpc.LedgerServiceStub(channel)

# Setup authentication metadata
metadata = [('x-api-key', API_TOKEN)]

# Example: Get object information
object_id = '0x5'

request = ledger_service_pb2.GetObjectRequest(
    object_id=object_id,
    read_mask=field_mask_pb2.FieldMask(
        paths=['object_id', 'version', 'digest', 'owner', 'object_type']
    )
)

try:
    response = client.GetObject(request, metadata=metadata)
    print(f'Object data: {response}')
except grpc.RpcError as e:
    print(f'Error: {e.code()}: {e.details()}')
finally:
    channel.close()
```

```bash
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client

# Initialize Go module
go mod init sui-grpc-client

# Install dependencies
go get google.golang.org/grpc
go get google.golang.org/protobuf

# Install protoc plugins for Go code generation
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

# Ensure Go bin is in PATH (add to ~/.zshrc or ~/.bash_profile for persistence)
export PATH="$PATH:$HOME/go/bin"

# Copy proto files from sui-apis repository
mkdir -p protos
cp -r ../proto/* protos/

# Add go_package option to all proto files
find protos/sui/rpc/v2 -name "*.proto" -type f | while read proto_file; do
    if ! grep -q "option go_package" "$proto_file"; then
        sed -i.bak '/^package sui.rpc.v2;$/a\
\
option go_package = "sui-grpc-client/sui/rpc/v2";
' "$proto_file"
    fi
done

# Generate Go code from proto files
protoc --go_out=. --go_opt=paths=source_relative \
  --go-grpc_out=. --go-grpc_opt=paths=source_relative \
  --proto_path=./protos \
  ./protos/sui/rpc/v2/*.proto
```

**Basic Client Example:**

```go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	pb "sui-grpc-client/sui/rpc/v2"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
)

const (
    // Dwellir gRPC endpoint
	endpoint = "api-sui-mainnet-full.n.dwellir.com:443"
	apiKey   = "api_key"
)

func main() {
	// Create TLS credentials for secure connection
	creds := credentials.NewClientTLSFromCert(nil, "")

	// Connect to Dwellir Sui gRPC server using NewClient (replaces deprecated Dial)
	conn, err := grpc.NewClient(
		endpoint,
		grpc.WithTransportCredentials(creds),
	)
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}
	defer conn.Close()

	client := pb.NewLedgerServiceClient(conn)

	// Setup authentication metadata with API key
    // Send the API key as metadata
	ctx := metadata.AppendToOutgoingContext(
		context.Background(),
		"x-api-key", apiKey,
	)

	// Set timeout
	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	// Get service info
	resp, err := client.GetServiceInfo(ctx, &pb.GetServiceInfoRequest{})
	if err != nil {
		log.Fatalf("GetServiceInfo failed: %v", err)
	}

	fmt.Printf("Connected to Sui Node via Dwellir\n")
	fmt.Printf("Chain: %s\n", resp.GetChain())
	fmt.Printf("Chain ID: %s\n", resp.GetChainId())
	fmt.Printf("Current Epoch: %d\n", resp.GetEpoch())
	fmt.Printf("Checkpoint Height: %d\n", resp.GetCheckpointHeight())
	fmt.Printf("Server: %s\n", resp.GetServer())
}
```

## Field Masking

gRPC requests support field masking to optimize response payloads and reduce bandwidth. Specify only the fields you need:

```typescript
const request = {
  object_id: '0x5',
  read_mask: {
    paths: ['object_id', 'version', 'owner'] // Only return these fields
  }
};
```

**Benefits:**

- Smaller responses when unused fields are omitted
- Faster serialization and network transfer
- Lower bandwidth costs
- Improved application performance

## Error Handling

gRPC provides standardized error codes for consistent error handling:

| Code                      | Description                | Action                |
| ------------------------- | -------------------------- | --------------------- |
| `OK` (0)                  | Success                    | Continue processing   |
| `CANCELLED` (1)           | Client cancelled           | Retry if needed       |
| `INVALID_ARGUMENT` (3)    | Invalid request parameters | Fix request and retry |
| `NOT_FOUND` (5)           | Resource not found         | Verify object IDs     |
| `ALREADY_EXISTS` (6)      | Resource exists            | Handle duplicate      |
| `PERMISSION_DENIED` (7)   | Authentication failed      | Check API token       |
| `RESOURCE_EXHAUSTED` (8)  | Rate limit exceeded        | Implement backoff     |
| `FAILED_PRECONDITION` (9) | System state invalid       | Retry later           |
| `UNAVAILABLE` (14)        | Service unavailable        | Retry with backoff    |
| `DEADLINE_EXCEEDED` (4)   | Request timeout            | Increase timeout      |

### Example Error Handling

TypeScript
Python

```typescript
client.GetObject(request, metadata, (error, response) => {
  if (error) {
    switch (error.code) {
      case grpc.status.NOT_FOUND:
        console.error('Object not found:', error.message);
        break;
      case grpc.status.PERMISSION_DENIED:
        console.error('Authentication failed. Check API token.');
        break;
      case grpc.status.RESOURCE_EXHAUSTED:
        console.error('Rate limit exceeded. Retrying after backoff...');
        // Implement exponential backoff
        break;
      case grpc.status.UNAVAILABLE:
        console.error('Service temporarily unavailable. Retrying...');
        // Retry with backoff
        break;
      default:
        console.error('Unexpected error:', error.message);
    }
    return;
  }

  // Process successful response
  console.log('Success:', response);
});
```

```python
import grpc
import time

def get_object_with_retry(client, request, metadata, max_retries=3):
    """Get object with automatic retry logic"""
    for attempt in range(max_retries):
        try:
            response = client.GetObject(request, metadata=metadata)
            return response
        except grpc.RpcError as e:
            code = e.code()

            if code == grpc.StatusCode.NOT_FOUND:
                print(f'Object not found: {e.details()}')
                return None
            elif code == grpc.StatusCode.PERMISSION_DENIED:
                print(f'Authentication failed: {e.details()}')
                return None
            elif code == grpc.StatusCode.RESOURCE_EXHAUSTED:
                wait_time = 2 ** attempt  # Exponential backoff
                print(f'Rate limited. Retrying in {wait_time}s...')
                time.sleep(wait_time)
            elif code == grpc.StatusCode.UNAVAILABLE:
                wait_time = 2 ** attempt
                print(f'Service unavailable. Retrying in {wait_time}s...')
                time.sleep(wait_time)
            else:
                print(f'Unexpected error: {code}: {e.details()}')
                return None

    print(f'Failed after {max_retries} attempts')
    return None
```

## Performance Optimization

### Reuse service clients

Create each service client once and reuse it across requests. Pass the endpoint string and TLS credentials to its constructor.

The [TypeScript setup guide](https://www.dwellir.com/docs/sui/grpc-setup-typescript) provides a working constructor and callback example. A `grpc.Client` object is not an endpoint string.

### Batch requests

Use `BatchGetObjects` for multiple object reads. Its request contains `requests`, an array of `GetObjectRequest` messages:

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"requests":[{"object_id":"0x5"},{"object_id":"0x6"}],"read_mask":{"paths":["object_id","version"]}}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/BatchGetObjects
```

Inspect each batch result for an error, even when the RPC succeeds. Node.js callback clients require a callback or an explicit Promise wrapper; awaiting a unary call object does not return its response.

### Field masks

Request the fields your application uses. Omitting `read_mask` selects method-specific defaults; it does not request every field.

`GetObject` defaults to `object_id`, `version`, and `digest`. Request `owner` explicitly when your application needs it:

```json
{
  "object_id": "0x5",
  "read_mask": {"paths": ["object_id", "version", "owner"]}
}
```

Read-mask roots vary by method. See each method's usage notes before reusing a mask across services.

## Real-Time Streaming

gRPC's streaming capabilities enable real-time blockchain monitoring:

### Checkpoint Subscription Example

```typescript
const subscriptionDefinition = protoLoader.loadSync(
  './protos/sui/rpc/v2/subscription_service.proto',
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: ['./protos']
  }
);
const subscriptionDescriptor = grpc.loadPackageDefinition(
  subscriptionDefinition
) as any;

const request = {
  read_mask: {
    paths: [
      'sequence_number',
      'digest',
      'summary.timestamp',
      'transactions.digest'
    ]
  }
};

const subscriptionClient = new subscriptionDescriptor.sui.rpc.v2.SubscriptionService(
  ENDPOINT,
  credentials
);
const stream = subscriptionClient.SubscribeCheckpoints(request, metadata);

stream.on('data', (response) => {
  const checkpoint = response.checkpoint;
  if (!checkpoint) return;

  console.log('New checkpoint:', {
    sequence: checkpoint.sequence_number,
    digest: checkpoint.digest,
    timestamp: checkpoint.summary?.timestamp,
    txCount: checkpoint.transactions?.length ?? 0
  });
});

stream.on('error', (error) => {
  console.error('Stream error:', error.message);
  // Implement reconnection logic
});

stream.on('end', () => {
  console.log('Stream ended');
});
```

`SubscribeCheckpoints` supports a server-side `TransactionFilter`. A checkpoint matches when any transaction it contains matches the filter. The checkpoint payload can still contain other transactions.

Filtered streams can send progress-only frames containing only a cursor. A missing checkpoint is not an error. Unfiltered streams deliver every checkpoint in order.

See [checkpoint recovery](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints#recover-after-a-disconnect) before persisting cursors or reconnecting.

## Server-side filters

`ListCheckpoints`, `ListTransactions`, and their subscriptions accept `TransactionFilter`. `ListEvents` and `SubscribeEvents` accept `EventFilter`.

Filters use disjunctive normal form: terms are ORed together, and literals within a term are ANDed together. Set `negated: true` to invert one literal.

An absent filter matches everything. An included filter must contain at least one term; `filter: {}` returns `INVALID_ARGUMENT`.

### Transaction filter example

Use this value as `filter` to match transactions from the zero address:

```json
{
  "terms": [{
    "literals": [{
      "sender": {
        "address": "0x0000000000000000000000000000000000000000000000000000000000000000"
      }
    }]
  }]
}
```

Transaction predicates are `sender`, `affected_address`, `affected_object`, `move_call`, `emit_module`, `event_type`, `event_stream_head`, and `package_write`.

| Predicate                    | Value fields                                             |
| ---------------------------- | -------------------------------------------------------- |
| `sender`, `affected_address` | `address`                                                |
| `affected_object`            | `object_id`                                              |
| `move_call`                  | `function`: `package[::module[::function]]`              |
| `emit_module`                | `module`: `package[::module]`                            |
| `event_type`                 | `event_type`: `address[::module[::Name[<type_params>]]]` |
| `event_stream_head`          | `stream_id`                                              |
| `package_write`              | Empty object `{}`                                        |

### Event filter example

This filter selects events whose declared type belongs to the Sui framework's `coin` module:

```json
{
  "terms": [{
    "literals": [{
      "event_type": {
        "event_type": "0x0000000000000000000000000000000000000000000000000000000000000002::coin"
      }
    }]
  }]
}
```

Event filters support `sender`, `emit_module`, `event_type`, and `event_stream_head`. Use the same value fields listed above.

Use full 32-byte hexadecimal addresses in Move paths. Short prefixes such as `0x2::coin` can be rejected by the filter parser.

`emit_module` matches the top-level Move call that triggered emission. `event_type` matches the declared event type. These packages can differ.

Every subscription frame carries progress. Transaction and event subscriptions use `watermark`; checkpoint subscriptions use `cursor`.

Use the corresponding `LedgerService.List*` method for retained filtered historical queries. GraphQL supports joined queries and historical data beyond full-node retention.

### Stream Management Best Practices

1. **Recover gaps on reconnect**: Persist the last cursor, compare it with the first cursor after reconnecting, and backfill missing checkpoints before processing buffered live data
2. **Handle backpressure**: Process data faster than it arrives or implement buffering
3. **Monitor connection health**: Use keepalive pings and heartbeats
4. **Graceful shutdown**: Close streams properly to avoid resource leaks

## Best Practices

### 1. Use Appropriate Timeouts

Set reasonable timeouts to prevent hanging requests:

```typescript
const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 10);

client.GetObject(request, metadata, { deadline }, (error, response) => {
  // Handle response
});
```

### 2. Implement Exponential Backoff

Handle rate limits and transient failures gracefully:

```typescript
async function retryWithBackoff(fn, maxRetries = 5) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      const waitTime = Math.min(1000 * Math.pow(2, i), 30000);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
  }
}
```

### 3. Monitor and Log

Track gRPC performance metrics:

```typescript
const call = client.GetObject(request, metadata, callback);

call.on('status', (status) => {
  console.log('RPC Status:', status.code, status.details);
});

call.on('metadata', (metadata) => {
  console.log('Server metadata:', metadata.getMap());
});
```

### 4. Validate Inputs

Validate request parameters before sending:

```typescript
function isValidObjectId(id: string): boolean {
  return /^0x[a-f0-9]+$/i.test(id);
}

if (!isValidObjectId(objectId)) {
  throw new Error('Invalid object ID format');
}
```

## Migration from JSON-RPC

Sui JSON-RPC clients stopped working after the full-node service was removed.
Migrating to gRPC requires generated clients and explicit request and response
mapping. Use the [complete migration guide](https://www.dwellir.com/docs/sui/json-rpc-removal) and this
table as a starting point:

| JSON-RPC                      | gRPC Equivalent                                  |
| ----------------------------- | ------------------------------------------------ |
| `sui_getObject`               | `LedgerService.GetObject`                        |
| `suix_getBalance`             | `StateService.GetBalance`                        |
| `sui_executeTransactionBlock` | `TransactionExecutionService.ExecuteTransaction` |
| `sui_subscribeEvent`          | `SubscriptionService.SubscribeEvents`            |
| `suix_queryTransactionBlocks` | `LedgerService.ListTransactions`                 |
| `suix_queryEvents`            | `LedgerService.ListEvents`                       |

### Example Migration

**Before (JSON-RPC):**

```typescript
const response = await fetch(endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'sui_getObject',
    params: [objectId],
    id: 1
  })
});
const data = await response.json();
```

**After (gRPC):**

```typescript
const response = await new Promise((resolve, reject) => {
  client.GetObject(
    { object_id: objectId },
    metadata,
    (error, response) => {
      if (error) reject(error);
      else resolve(response);
    }
  );
});
```

## Troubleshooting

### Common Issues

**Connection Refused**

- Verify port 443 is used for gRPC
- Check firewall settings allow outbound connections on port 443
- Ensure TLS credentials are properly configured

**Authentication Errors**

- Verify API token is correct and active
- Check token is passed in `x-api-key` metadata header
- Confirm endpoint URL matches your Dwellir account

**Timeout Errors**

- Increase request timeout/deadline
- Check network connectivity and latency
- Verify endpoint availability via Dwellir dashboard

**Protocol Buffer Errors**

- Ensure proto files match server version
- Regenerate client code after proto updates
- Check import paths and dependencies

## Support and Resources

### Documentation

- [Complete gRPC Method Reference](https://www.dwellir.com/docs/sui#api-reference) - All 28 methods
- [Ledger Service Methods](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info) - Object and transaction queries
- [State Service Methods](https://www.dwellir.com/docs/sui/grpc/state/get-balance) - Current state queries
- [Subscription Service](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) - Checkpoint, transaction, and event streams

### Getting Help

- **Email**: <support@dwellir.com>
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Status Page**: Monitor service health and incidents

### Additional Resources

- [Sui Official Documentation](https://docs.sui.io)

***

*Ready to build with gRPC? [Get your API key](https://dashboard.dwellir.com) and experience the performance difference with Dwellir's enterprise-grade Sui infrastructure.*

---

## Go Client for Sui gRPC

# Go Client for Sui gRPC

Generate clients from the official Sui v2 definitions. The import mappings below keep generated files in one Go package.

## Install dependencies

Install the Protocol Buffers compiler, `protoc`, through your system package manager. Then create the client project:

```bash
mkdir sui-grpc-go
cd sui-grpc-go
go mod init example.com/sui-grpc

go get google.golang.org/grpc google.golang.org/protobuf
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
export PATH="$(go env GOPATH)/bin:$PATH"

git clone --depth 1 https://github.com/MystenLabs/sui-apis.git
mkdir -p protos gen
cp -R sui-apis/proto/. protos/
```

## Generate client code

Run this block in Bash. It supplies import mappings without editing the upstream proto files.

```bash
mapping=()
for file in protos/sui/rpc/v2/*.proto; do
  relative=${file#protos/}
  target=example.com/sui-grpc/gen/sui/rpc/v2
  mapping+=("--go_opt=M${relative}=${target}")
  mapping+=("--go-grpc_opt=M${relative}=${target}")
done

protoc -I./protos \
  --go_out=./gen --go_opt=paths=source_relative \
  --go-grpc_out=./gen --go-grpc_opt=paths=source_relative \
  "${mapping[@]}" ./protos/sui/rpc/v2/*.proto

go mod tidy
```

## Query service information

Save this as `main.go`:

```go
package main

import (
    "context"
    "crypto/tls"
    "fmt"
    "log"
    "os"
    "time"

    pb "example.com/sui-grpc/gen/sui/rpc/v2"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    apiKey := os.Getenv("DWELLIR_API_KEY")
    if apiKey == "" {
        log.Fatal("Set DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(
        "api-sui-mainnet-full.n.dwellir.com:443",
        grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
            MinVersion: tls.VersionTLS12,
        })),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
    response, err := pb.NewLedgerServiceClient(conn).GetServiceInfo(
        ctx, &pb.GetServiceInfoRequest{},
    )
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(response.GetChain(), response.GetServer(), response.GetCheckpointHeight())
}
```

Set `DWELLIR_API_KEY` in your environment, then run:

```bash
go mod tidy
go run .
```

## Use other services

The execution client is `pb.NewTransactionExecutionServiceClient(conn)`.

Object reads return `response.GetObject()`. Epoch reads return `response.GetEpoch()`, which is an epoch message, not an integer.

Use [method-specific references](https://www.dwellir.com/docs/sui#api-reference) for request fields and envelopes. See [checkpoint subscriptions](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) for stream cancellation and recovery.

---

## Using grpcurl with Sui gRPC

# Using grpcurl with Sui gRPC

`grpcurl` uses server reflection to discover Dwellir's deployed Sui API. You do not need local proto files for these commands.

## Install grpcurl

Install a binary from the [grpcurl releases](https://github.com/fullstorydev/grpcurl/releases), or build it with Go:

```bash
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
export PATH="$(go env GOPATH)/bin:$PATH"
```

## Configure authentication

Set `DWELLIR_API_KEY` in your environment. The commands below expand that variable inside grpcurl, so the key is absent from the process arguments.

```bash
export SUI_GRPC_ENDPOINT=api-sui-mainnet-full.n.dwellir.com:443
```

Use TLS on port 443. Pass authentication as `x-api-key` metadata, rather than appending the key to the URL.

## Discover services and messages

```bash
grpcurl -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  "$SUI_GRPC_ENDPOINT" list

grpcurl -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  "$SUI_GRPC_ENDPOINT" list sui.rpc.v2.TransactionExecutionService

grpcurl -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  "$SUI_GRPC_ENDPOINT" describe sui.rpc.v2.ExecuteTransactionRequest
```

The execution service is `TransactionExecutionService`. Inspect request messages before constructing a payload; reflection lists schemas, rather than testing method behavior.

## Query service information

```bash
grpcurl -max-time 10 -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  -d '{}' "$SUI_GRPC_ENDPOINT" sui.rpc.v2.LedgerService/GetServiceInfo
```

The response includes `checkpointHeight`, `lowestAvailableCheckpoint`, and `lowestAvailableCheckpointObjects`. Those values change as the node advances and prunes data.

## Read the latest checkpoint

```bash
grpcurl -max-time 10 -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  -d '{"read_mask":{"paths":["sequence_number","summary.timestamp"]}}' \
  "$SUI_GRPC_ENDPOINT" sui.rpc.v2.LedgerService/GetCheckpoint
```

The selected fields appear inside `checkpoint`. The timestamp is `checkpoint.summary.timestamp`, rather than `timestamp_ms`.

## Read balances and package functions

```bash
grpcurl -max-time 10 -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  -d '{"owner":"0x0","coin_type":"0x2::sui::SUI"}' \
  "$SUI_GRPC_ENDPOINT" sui.rpc.v2.StateService/GetBalance

grpcurl -max-time 10 -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  -d '{"package_id":"0x2","module_name":"transfer","name":"transfer"}' \
  "$SUI_GRPC_ENDPOINT" sui.rpc.v2.MovePackageService/GetFunction
```

Balance data appears inside `balance`. A package member request uses `name`, not `function_name` or `datatype_name`.

## Choose a recent historical range

This example also requires `jq`:

```bash
checkpoint=$(grpcurl -max-time 10 -expand-headers \
  -H 'x-api-key: ${DWELLIR_API_KEY}' -d '{}' "$SUI_GRPC_ENDPOINT" \
  sui.rpc.v2.LedgerService/GetServiceInfo | jq -r '.checkpointHeight | tonumber - 10')

request=$(jq -n --arg checkpoint "$checkpoint" \
  '{start_checkpoint:$checkpoint,options:{limit:2},read_mask:{paths:["sequence_number"]}}')

grpcurl -max-time 10 -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  -d "$request" "$SUI_GRPC_ENDPOINT" sui.rpc.v2.LedgerService/ListCheckpoints
```

The start bound is inclusive. An end bound, when supplied, is exclusive. The final frame includes `end`.

A range below retained history returns `OUT_OF_RANGE`. Individual checkpoint and proof reads can return `NOT_FOUND` for pruned or unindexed data.

## Test live streams

```bash
grpcurl -max-time 5 -expand-headers -H 'x-api-key: ${DWELLIR_API_KEY}' \
  -d '{"read_mask":{"paths":["sequence_number"]}}' \
  "$SUI_GRPC_ENDPOINT" sui.rpc.v2.SubscriptionService/SubscribeCheckpoints
```

The client deadline terminates this unbounded stream. `DEADLINE_EXCEEDED` after receiving frames is expected for this command.

Filtered subscriptions can emit progress-only frames. See [filter syntax](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters) and [recovery guidance](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints).

## Execute or simulate transactions

Follow the [execution](https://www.dwellir.com/docs/sui/grpc/transaction/execute) and [simulation](https://www.dwellir.com/docs/sui/grpc/state/simulate-transaction) references for encoded transaction bodies and mask roots.

Put serialized transaction bytes in `transaction.bcs.value`. Successful execution submits a signed transaction; simulation does not.

---

## Python Client for Sui gRPC

# Python Client for Sui gRPC

Generate the v2 clients, then call `LedgerService.GetServiceInfo`. The service reports the network, node version, checkpoint height, and retention bounds.

## Install dependencies

```bash
mkdir sui-grpc-python
cd sui-grpc-python
python3 -m venv .venv
source .venv/bin/activate
pip install grpcio grpcio-tools googleapis-common-protos

git clone --depth 1 https://github.com/MystenLabs/sui-apis.git
mkdir -p protos
cp -R sui-apis/proto/. protos/
```

## Generate all Sui v2 client stubs

```bash
PROTO_INCLUDE=$(python -c 'import grpc_tools, pathlib; print(pathlib.Path(grpc_tools.__file__).parent / "_proto")')
python -m grpc_tools.protoc \
  -I./protos -I"$PROTO_INCLUDE" \
  --python_out=. --grpc_python_out=. \
  ./protos/sui/rpc/v2/*.proto
```

Keep the complete directory tree. Generated modules import other Sui v2 messages and Google protobuf types.

## Query service information

Save this as `client.py`:

```python
import os
import grpc
from sui.rpc.v2 import ledger_service_pb2, ledger_service_pb2_grpc

endpoint = 'api-sui-mainnet-full.n.dwellir.com:443'
metadata = [('x-api-key', os.environ['DWELLIR_API_KEY'])]

with grpc.secure_channel(endpoint, grpc.ssl_channel_credentials()) as channel:
    client = ledger_service_pb2_grpc.LedgerServiceStub(channel)
    response = client.GetServiceInfo(
        ledger_service_pb2.GetServiceInfoRequest(),
        metadata=metadata,
        timeout=10,
    )
    print(response.chain, response.server, response.checkpoint_height)
```

Set `DWELLIR_API_KEY` in your environment, then run:

```bash
python client.py
```

Python protobuf fields use snake\_case. Responses retain their envelopes: object reads return `response.object`, and epoch reads return `response.epoch`.

## Use a field mask

```python
from google.protobuf import field_mask_pb2

request = ledger_service_pb2.GetObjectRequest(
    object_id='0x5',
    read_mask=field_mask_pb2.FieldMask(paths=['object_id', 'version']),
)
```

Call `GetObject` with this request inside an open channel. The mask applies to `response.object`, rather than the outer response message.

## Execution and subscriptions

The execution stub is `transaction_execution_service_pb2_grpc.TransactionExecutionServiceStub`.

Serialized bytes belong in `Transaction.bcs.value`. A serialized signature belongs in `UserSignature.bcs.value`.

See [ExecuteTransaction](https://www.dwellir.com/docs/sui/grpc/transaction/execute) and [SimulateTransaction](https://www.dwellir.com/docs/sui/grpc/state/simulate-transaction) for their different mask roots.

Subscriptions require cancellation, bounded processing, and persisted progress. See [SubscribeCheckpoints](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) before building a recovery loop.

Check the [deployed schema with grpcurl](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl) when regenerating clients.

---

## TypeScript Client for Sui gRPC

# TypeScript Client for Sui gRPC

This example runs in Node.js. It loads the official v2 service definitions and queries the node version and current checkpoint.

## Install dependencies

```bash
mkdir sui-grpc-ts
cd sui-grpc-ts
npm init -y
npm install @grpc/grpc-js @grpc/proto-loader
npm install --save-dev typescript tsx @types/node

git clone --depth 1 https://github.com/MystenLabs/sui-apis.git
mkdir -p protos
cp -R sui-apis/proto/. protos/
```

Keep the full `sui/rpc/v2/` directory and its imports. The service filename is `ledger_service.proto`.

## Query service information

Save this as `client.ts`:

```typescript
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

type ServiceInfo = {
  chain?: string;
  server?: string;
  checkpoint_height?: string;
};
type LedgerClient = grpc.Client & {
  GetServiceInfo(
    request: Record<string, never>,
    metadata: grpc.Metadata,
    options: grpc.CallOptions,
    callback: grpc.requestCallback<ServiceInfo>,
  ): grpc.ClientUnaryCall;
};
type Services = {
  sui: { rpc: { v2: { LedgerService: grpc.ServiceClientConstructor } } };
};

const definition = protoLoader.loadSync(
  'sui/rpc/v2/ledger_service.proto',
  { keepCase: true, longs: String, includeDirs: ['./protos'] },
);
const services = grpc.loadPackageDefinition(definition) as unknown as Services;
const client = new services.sui.rpc.v2.LedgerService(
  'api-sui-mainnet-full.n.dwellir.com:443',
  grpc.credentials.createSsl(),
) as unknown as LedgerClient;

const apiKey = process.env.DWELLIR_API_KEY;
if (!apiKey) throw new Error('Set DWELLIR_API_KEY');
const metadata = new grpc.Metadata();
metadata.set('x-api-key', apiKey);

client.GetServiceInfo({}, metadata, { deadline: Date.now() + 10_000 }, (error, response) => {
  try {
    if (error) throw error;
    console.log(response);
  } finally {
    client.close();
  }
});
```

Set `DWELLIR_API_KEY` in your environment, then run:

```bash
npx tsx client.ts
```

`keepCase: true` preserves snake\_case fields. Protobuf `uint64` values remain strings, which avoids JavaScript integer precision loss.

## Add other services

Load each service's actual file and constructor:

| Service                        | Proto file                             |
| ------------------------------ | -------------------------------------- |
| `StateService`                 | `state_service.proto`                  |
| `MovePackageService`           | `move_package_service.proto`           |
| `TransactionExecutionService`  | `transaction_execution_service.proto`  |
| `SubscriptionService`          | `subscription_service.proto`           |
| `SignatureVerificationService` | `signature_verification_service.proto` |
| `NameService`                  | `name_service.proto`                   |

Method responses have envelopes. For example, `GetObject` returns `response.object`, and `GetBalance` returns `response.balance`.

Use the [execution reference](https://www.dwellir.com/docs/sui/grpc/transaction/execute) for transaction and signature encoding. Use the [subscription guide](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints) for stream recovery.

Browser applications need a compatible browser transport or a server-side integration. This Node.js example uses native HTTP/2 gRPC.

## Check the deployed schema

Use [grpcurl reflection](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl) to inspect the endpoint before generating or updating clients. The [gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview) lists all supported methods.

---

## BatchGetObjects - Efficient Bulk Object Retrieval

# BatchGetObjects - Efficient Bulk Object Retrieval

Retrieve multiple Sui objects in a single gRPC request for maximum efficiency. Learn how to use BatchGetObjects to minimize latency and optimize blockchain data fetching with Dwellir's Sui infrastructure.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `BatchGetObjects`
- **Type:** Unary RPC

## Request Parameters

- `requests` (`GetObjectRequest[], required`): Object requests in response order.
- `read_mask` (`FieldMask, optional`): Fields of Object to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "requests": [
    {
      "object_id": "0x5"
    },
    {
      "object_id": "0x6"
    }
  ],
  "read_mask": {
    "paths": [
      "object_id",
      "version"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/BatchGetObjects
```

## Response Fields

- `objects` (`GetObjectResult[], optional`): Requested objects, or ordered per-item object results for batch requests.

## Successful Response

```protobuf
message BatchGetObjectsResponse {
  repeated GetObjectResult objects = 1;
}
```

## Usage notes

The response preserves request order. A successful RPC can contain per-item errors; inspect every result.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## BatchGetTransactions - Retrieve Multiple Sui Transactions

# BatchGetTransactions - Retrieve Multiple Sui Transactions

Retrieve multiple Sui transactions by digest in one gRPC request, with per-item results and field-mask control.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `BatchGetTransactions`
- **Type:** Unary RPC

## Request Parameters

- `digests` (`string[], required`): Transaction digests in response order.
- `read_mask` (`FieldMask, optional`): Fields of ExecutedTransaction to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "digests": [
    "TRANSACTION_DIGEST"
  ],
  "read_mask": {
    "paths": [
      "digest",
      "effects.status"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/BatchGetTransactions
```

## Response Fields

- `transactions` (`GetTransactionResult[], optional`): Ordered per-item transaction results. Inspect each item for an error.

## Successful Response

```protobuf
message BatchGetTransactionsResponse {
  repeated GetTransactionResult transactions = 1;
}
```

## Usage notes

Replace `TRANSACTION_DIGEST` with a digest from [ListTransactions](https://www.dwellir.com/docs/sui/grpc/ledger/list-transactions). Inspect every result for a per-item error.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetCheckpoint - Query Finalized Blockchain State

# GetCheckpoint - Query Finalized Blockchain State

Retrieve Sui blockchain checkpoints via gRPC to access finalized state, transaction batches, and validator signatures. Essential for applications requiring guaranteed finality with Dwellir's infrastructure.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `GetCheckpoint`
- **Type:** Unary RPC

## Request Parameters

- `sequence_number` (`uint64, optional`): Checkpoint sequence number. Omit both selectors for the latest executed checkpoint.
- `digest` (`string, optional`): Checkpoint digest to retrieve. Use either digest or sequence_number.
- `read_mask` (`FieldMask, optional`): Fields of Checkpoint to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "read_mask": {
    "paths": [
      "sequence_number",
      "digest",
      "summary.timestamp"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetCheckpoint
```

## Response Fields

- `checkpoint` (`Checkpoint, optional`): Requested checkpoint data, wrapped in the response.

## Successful Response

```protobuf
message GetCheckpointResponse {
  optional Checkpoint checkpoint = 1;
}
```

## Usage notes

Omit both selectors to fetch the latest executed checkpoint. Choose either `sequence_number` or `digest`, never both. Timestamp is `checkpoint.summary.timestamp`.

Historical data is limited by node retention. Check `lowest_available_checkpoint` and `lowest_available_checkpoint_objects` with [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). Use an archival source when data has been pruned.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetEpoch - Query Epoch Information

# GetEpoch - Query Epoch Information

Retrieve Sui epoch information via gRPC including validators, stake distribution, and timing. Essential for staking applications and network monitoring with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `GetEpoch`
- **Type:** Unary RPC

## Request Parameters

- `epoch` (`uint64, optional`): Epoch number. Omit for the current epoch.
- `read_mask` (`FieldMask, optional`): Fields of Epoch to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "read_mask": {
    "paths": [
      "epoch",
      "reference_gas_price"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetEpoch
```

## Response Fields

- `epoch` (`Epoch, optional`): Requested epoch data, wrapped in the response.

## Successful Response

```protobuf
message GetEpochResponse {
  optional Epoch epoch = 1;
}
```

## Usage notes

Use `epoch`, not `epoch_id`, to select an epoch. The response wraps data in `epoch`. Validator membership is `epoch.committee`.

Historical data is limited by node retention. Check `lowest_available_checkpoint` and `lowest_available_checkpoint_objects` with [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). Use an archival source when data has been pruned.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetObject - Retrieve Sui Object Data via gRPC

# GetObject - Retrieve Sui Object Data via gRPC

Retrieve detailed Sui blockchain object information using the gRPC GetObject method. Access object metadata, ownership, version history, and contents with high-performance binary serialization through Dwellir's infrastructure.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `GetObject`
- **Type:** Unary RPC

## Request Parameters

- `object_id` (`string, required`): Object ID to retrieve.
- `version` (`uint64, optional`): Object version to retrieve. Omit for the latest version.
- `read_mask` (`FieldMask, optional`): Fields of Object to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "object_id": "0x5",
  "read_mask": {
    "paths": [
      "object_id",
      "version",
      "object_type"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetObject
```

## Response Fields

- `object` (`Object, optional`): Requested object, wrapped in the response.

## Successful Response

```protobuf
message GetObjectResponse {
  optional Object object = 1;
}
```

## Usage notes

The response wraps the selected fields in `object`. Versioned reads can fail after object history is pruned.

Historical data is limited by node retention. Check `lowest_available_checkpoint` and `lowest_available_checkpoint_objects` with [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). Use an archival source when data has been pruned.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetServiceInfo - Inspect Sui Node State via gRPC

# GetServiceInfo - Inspect Sui Node State via gRPC

`LedgerService.GetServiceInfo` returns the node's current network identity and synchronization position. Use it for readiness checks, version discovery, and retention-aware recovery.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `GetServiceInfo`
- **Type:** Unary RPC

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetServiceInfo
```

## Response Fields

- `chain_id` (`string, optional`): Digest of the genesis checkpoint.
- `chain` (`string, optional`): Network name.
- `epoch` (`uint64, optional`): Epoch at the highest executed checkpoint.
- `checkpoint_height` (`uint64, optional`): Highest executed checkpoint.
- `timestamp` (`Timestamp, optional`): Timestamp of the highest executed checkpoint.
- `lowest_available_checkpoint` (`uint64, optional`): Earliest retained checkpoint and transaction data.
- `lowest_available_checkpoint_objects` (`uint64, optional`): Earliest retained object data.
- `server` (`string, optional`): Node software version.

## Successful Response

```protobuf
message GetServiceInfoResponse {
  optional string chain_id = 1;
  optional string chain = 2;
  optional uint64 epoch = 3;
  optional uint64 checkpoint_height = 4;
  optional Timestamp timestamp = 5;
  optional uint64 lowest_available_checkpoint = 6;
  optional uint64 lowest_available_checkpoint_objects = 7;
  optional string server = 8;
}
```

The `checkpoint_height` field identifies the highest executed checkpoint. Compare it across requests to confirm advancement. Before backfilling older data, compare the required checkpoint with `lowest_available_checkpoint` and `lowest_available_checkpoint_objects`.

## Related Methods

- [GetCheckpoint](https://www.dwellir.com/docs/sui/grpc/ledger/get-checkpoint)
- [ListCheckpoints](https://www.dwellir.com/docs/sui/grpc/ledger/list-checkpoints)
- [SubscribeCheckpoints](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints)

See the [official Sui gRPC schema](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/ledger_service.proto) for the current protobuf definition.

---

## GetTransaction - Query Transaction Details

# GetTransaction - Query Transaction Details

Retrieve comprehensive Sui transaction details via gRPC including effects, events, and state changes. Perfect for transaction verification and blockchain analytics with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `GetTransaction`
- **Type:** Unary RPC

## Request Parameters

- `digest` (`string, required`): Transaction digest to retrieve.
- `read_mask` (`FieldMask, optional`): Fields of ExecutedTransaction to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "digest": "TRANSACTION_DIGEST",
  "read_mask": {
    "paths": [
      "digest",
      "checkpoint",
      "timestamp"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetTransaction
```

## Response Fields

- `transaction` (`ExecutedTransaction, optional`): Executed transaction data, wrapped in the response.

## Successful Response

```protobuf
message GetTransactionResponse {
  optional ExecutedTransaction transaction = 1;
}
```

## Usage notes

Replace `TRANSACTION_DIGEST` with a digest from [ListTransactions](https://www.dwellir.com/docs/sui/grpc/ledger/list-transactions). The response wraps data in `transaction`.

Historical data is limited by node retention. Check `lowest_available_checkpoint` and `lowest_available_checkpoint_objects` with [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). Use an archival source when data has been pruned.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## ListCheckpoints - Stream Historical Sui Checkpoints

# ListCheckpoints - Stream Historical Sui Checkpoints

`LedgerService.ListCheckpoints` runs a bounded historical scan and streams matching checkpoints. Every frame includes a watermark; the final successful frame also includes a query-end reason.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `ListCheckpoints`
- **Type:** Server-streaming RPC

## Request Parameters

- `read_mask` (`FieldMask, optional`): Fields of Checkpoint to return. Use paths relative to that message.
- `start_checkpoint` (`uint64, optional`): Inclusive checkpoint lower bound. Omit to start at the earliest retained checkpoint.
- `end_checkpoint` (`uint64, optional`): Exclusive checkpoint upper bound. Omit to scan up to the indexed tip.
- `filter` (`TransactionFilter, optional`): Optional server-side filter. An included filter must contain at least one term.
- `options` (`QueryOptions, optional`): Scan limit, cursor bounds, and ordering. Use options.after for ascending continuation.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "start_checkpoint": "RECENT_CHECKPOINT",
  "options": {
    "limit": 2
  },
  "read_mask": {
    "paths": [
      "sequence_number",
      "digest"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/ListCheckpoints
```

## Response Fields

- `checkpoint` (`Checkpoint, optional`): Checkpoint data. Filtered progress frames can omit this field.
- `watermark` (`Watermark, optional`): Progress and continuation cursor. Present even when a frame contains no matching item.
- `end` (`QueryEnd, optional`): Scan end reason on the final successful frame.

## Successful Response

```protobuf
message ListCheckpointsResponse {
  optional Checkpoint checkpoint = 1;
  optional Watermark watermark = 2;
  optional QueryEnd end = 3;
}
```

## Error Responses

### Range outside retained history

- Code: `OUT_OF_RANGE`
- Description: The lower bound predates retained history. Check GetServiceInfo and use an archival source for older data.

`start_checkpoint` is inclusive and `end_checkpoint` is exclusive. To continue an ascending scan, pass the last watermark cursor as `options.after`.

## Related Methods

- [GetCheckpoint](https://www.dwellir.com/docs/sui/grpc/ledger/get-checkpoint)
- [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info)
- [SubscribeCheckpoints](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints)

See the [official Sui gRPC schema](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/ledger_service.proto) for the current protobuf definition.

## Retention and filters

Replace `RECENT_CHECKPOINT` with a recent `checkpointHeight` from [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). A lower bound before retained history returns `OUT_OF_RANGE`.

See [filter syntax and examples](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters) before adding a `filter`. An included filter must contain at least one term.

---

## ListEvents - Stream Historical Sui Events

# ListEvents - Stream Historical Sui Events

`LedgerService.ListEvents` streams matching Move events from the indexed ledger. Each event carries its checkpoint, transaction digest, transaction index, and event index when requested.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `ListEvents`
- **Type:** Server-streaming RPC

## Request Parameters

- `read_mask` (`FieldMask, optional`): Fields of Event to return. Use paths relative to that message.
- `start_checkpoint` (`uint64, optional`): Inclusive checkpoint lower bound. Omit to start at the earliest retained checkpoint.
- `end_checkpoint` (`uint64, optional`): Exclusive checkpoint upper bound. Omit to scan up to the indexed tip.
- `filter` (`EventFilter, optional`): Optional server-side filter. An included filter must contain at least one term.
- `options` (`QueryOptions, optional`): Scan limit, cursor bounds, and ordering. Use options.after for ascending continuation.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "start_checkpoint": "RECENT_CHECKPOINT",
  "options": {
    "limit": 2
  },
  "read_mask": {
    "paths": [
      "checkpoint",
      "transaction_digest",
      "event_index",
      "event_type"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/ListEvents
```

## Response Fields

- `event` (`Event, optional`): Requested event.
- `watermark` (`Watermark, optional`): Progress and continuation cursor. Present even when a frame contains no matching item.
- `end` (`QueryEnd, optional`): Scan end reason on the final successful frame.

## Successful Response

```protobuf
message ListEventsResponse {
  optional Event event = 1;
  optional Watermark watermark = 2;
  optional QueryEnd end = 3;
}
```

## Error Responses

### Range outside retained history

- Code: `OUT_OF_RANGE`
- Description: The lower bound predates retained history. Check GetServiceInfo and use an archival source for older data.

Use `event_type` to identify the declared event type. `package_id` and `module` identify the top-level Move call that triggered emission and can differ from the event type's package and module.

## Related Methods

- [ListTransactions](https://www.dwellir.com/docs/sui/grpc/ledger/list-transactions)
- [SubscribeEvents](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-events)

See the [official Sui gRPC schema](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/ledger_service.proto) for the current protobuf definition.

## Retention and filters

Replace `RECENT_CHECKPOINT` with a recent `checkpointHeight` from [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). A lower bound before retained history returns `OUT_OF_RANGE`.

See [filter syntax and examples](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters) before adding a `filter`. An included filter must contain at least one term.

For recovery and deduplication, include both `transaction_digest` and `event_index` in the subscription and replay masks. Different events from one transaction share its digest.

---

## ListTransactions - Stream Historical Sui Transactions

# ListTransactions - Stream Historical Sui Transactions

`LedgerService.ListTransactions` streams transactions from a bounded historical scan. Filters, checkpoint bounds, and opaque cursors let indexers backfill without loading complete checkpoints.

## Method Signature

- **Service:** `sui.rpc.v2.LedgerService`
- **Method:** `ListTransactions`
- **Type:** Server-streaming RPC

## Request Parameters

- `read_mask` (`FieldMask, optional`): Fields of ExecutedTransaction to return. Use paths relative to that message.
- `start_checkpoint` (`uint64, optional`): Inclusive checkpoint lower bound. Omit to start at the earliest retained checkpoint.
- `end_checkpoint` (`uint64, optional`): Exclusive checkpoint upper bound. Omit to scan up to the indexed tip.
- `filter` (`TransactionFilter, optional`): Optional server-side filter. An included filter must contain at least one term.
- `options` (`QueryOptions, optional`): Scan limit, cursor bounds, and ordering. Use options.after for ascending continuation.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "start_checkpoint": "RECENT_CHECKPOINT",
  "options": {
    "limit": 2
  },
  "read_mask": {
    "paths": [
      "digest",
      "transaction.sender"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/ListTransactions
```

## Response Fields

- `transaction` (`ExecutedTransaction, optional`): Executed transaction data, wrapped in the response.
- `watermark` (`Watermark, optional`): Progress and continuation cursor. Present even when a frame contains no matching item.
- `end` (`QueryEnd, optional`): Scan end reason on the final successful frame.

## Successful Response

```protobuf
message ListTransactionsResponse {
  optional ExecutedTransaction transaction = 1;
  optional Watermark watermark = 2;
  optional QueryEnd end = 3;
}
```

## Error Responses

### Range outside retained history

- Code: `OUT_OF_RANGE`
- Description: The lower bound predates retained history. Check GetServiceInfo and use an archival source for older data.

Persist the latest watermark only after downstream processing succeeds. Resume ascending scans with `options.after`, or descending scans with `options.before`.

## Related Methods

- [GetTransaction](https://www.dwellir.com/docs/sui/grpc/ledger/get-transaction)
- [BatchGetTransactions](https://www.dwellir.com/docs/sui/grpc/ledger/batch-get-transactions)
- [SubscribeTransactions](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-transactions)

See the [official Sui gRPC schema](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/ledger_service.proto) for the current protobuf definition.

## Retention and filters

Replace `RECENT_CHECKPOINT` with a recent `checkpointHeight` from [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). A lower bound before retained history returns `OUT_OF_RANGE`.

See [filter syntax and examples](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters) before adding a `filter`. An included filter must contain at least one term.

---

## LookupName - Resolve a SuiNS Name via gRPC

# LookupName - Resolve a SuiNS Name via gRPC

Resolve a SuiNS name to its on-chain record, target address, registration NFT, expiration, and attached data over gRPC.

## Method Signature

- **Service:** `sui.rpc.v2.NameService`
- **Method:** `LookupName`
- **Type:** Unary RPC

## Request Parameters

- `name` (`string, required`): SuiNS name in @name or name.sui format.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "name": "walrus.sui"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.NameService/LookupName
```

## Response Fields

- `record` (`NameRecord, optional`): Forward or reverse SuiNS record.

## Successful Response

```protobuf
message LookupNameResponse {
  optional NameRecord record = 1;
}
```

## Error Responses

### Record not found

- Code: `NOT_FOUND`
- Description: No name or reverse record exists for the requested value.

## Usage notes

The example resolves `walrus.sui`. A registered name can have no `target_address`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## ReverseLookupName - Resolve a Sui Address to SuiNS

# ReverseLookupName - Resolve a Sui Address to SuiNS

Resolve a 32-byte Sui address to its configured reverse SuiNS record through Dwellir's gRPC endpoint.

## Method Signature

- **Service:** `sui.rpc.v2.NameService`
- **Method:** `ReverseLookupName`
- **Type:** Unary RPC

## Request Parameters

- `address` (`string, required`): Sui address whose configured reverse SuiNS record is requested.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "address": "SUI_ADDRESS"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.NameService/ReverseLookupName
```

## Response Fields

- `record` (`NameRecord, optional`): Forward or reverse SuiNS record.

## Successful Response

```protobuf
message ReverseLookupNameResponse {
  optional NameRecord record = 1;
}
```

## Error Responses

### Record not found

- Code: `NOT_FOUND`
- Description: No name or reverse record exists for the requested value.

## Usage notes

Replace `SUI_ADDRESS` with the `targetAddress` from a [LookupName](https://www.dwellir.com/docs/sui/grpc/name/lookup-name) response for a name with a configured reverse record. An address can return `NOT_FOUND`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetDatatype - Query Move Struct Definitions

# GetDatatype - Query Move Struct Definitions

Retrieve Move struct and datatype definitions via gRPC including fields and type parameters. Essential for understanding smart contract data structures with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.MovePackageService`
- **Method:** `GetDatatype`
- **Type:** Unary RPC

## Request Parameters

- `package_id` (`string, required`): Storage ID of the package containing the datatype.
- `module_name` (`string, required`): Move module name within the package.
- `name` (`string, required`): Name of the Move datatype within the module.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "package_id": "0x2",
  "module_name": "coin",
  "name": "Coin"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.MovePackageService/GetDatatype
```

## Response Fields

- `datatype` (`DatatypeDescriptor, optional`): Requested Move datatype descriptor.

## Successful Response

```protobuf
message GetDatatypeResponse {
  optional DatatypeDescriptor datatype = 1;
}
```

## Usage notes

The request field is `name`, not `datatype_name`. The response wraps the descriptor in `datatype`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetFunction - Query Move Function Details

# GetFunction - Query Move Function Details

Retrieve detailed Move function information via gRPC including parameters, return types, and visibility. Essential for smart contract integration with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.MovePackageService`
- **Method:** `GetFunction`
- **Type:** Unary RPC

## Request Parameters

- `package_id` (`string, required`): Storage ID of the package containing the function.
- `module_name` (`string, required`): Move module name within the package.
- `name` (`string, required`): Name of the Move function within the module.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "package_id": "0x2",
  "module_name": "transfer",
  "name": "transfer"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.MovePackageService/GetFunction
```

## Response Fields

- `function` (`FunctionDescriptor, optional`): Requested Move function descriptor.

## Successful Response

```protobuf
message GetFunctionResponse {
  optional FunctionDescriptor function = 1;
}
```

## Usage notes

The request field is `name`, not `function_name`. The response wraps the descriptor in `function`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetPackage - Query Move Package Details

# GetPackage - Query Move Package Details

Retrieve comprehensive Move package information via gRPC including modules, functions, and datatypes. Essential for smart contract exploration with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.MovePackageService`
- **Method:** `GetPackage`
- **Type:** Unary RPC

## Request Parameters

- `package_id` (`string, required`): Storage ID of the package. Selectors identify a version within its upgrade lineage.
- `version` (`uint64, optional`): Exact lineage version to request. Mutually exclusive with at_checkpoint. Verify the returned version for framework packages.
- `at_checkpoint` (`uint64, optional`): Latest package version at or before this checkpoint. Mutually exclusive with version.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "package_id": "0x2"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.MovePackageService/GetPackage
```

## Response Fields

- `package` (`Package, optional`): Requested package data.

## Successful Response

```protobuf
message GetPackageResponse {
  optional Package package = 1;
}
```

## Usage notes

Choose at most one selector: `version` or `at_checkpoint`. Without either selector, the exact package at `package_id` is returned. This method has no read mask.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

## Framework package versions

Framework packages such as `0x2` can reuse one storage ID across multiple versions. On `sui-node/1.82.3`, an older `version` selector can return the current package at that ID.

Compare `package.version` with the requested version before treating the result as historical bytecode. Omitting both selectors still returns the exact package currently stored at `package_id`.

---

## ListPackageVersions - Query Sui Package Upgrade History

# ListPackageVersions - Query Sui Package Upgrade History

List every published version in a Sui Move package upgrade lineage with cursor-based pagination over Dwellir gRPC.

## Method Signature

- **Service:** `sui.rpc.v2.MovePackageService`
- **Method:** `ListPackageVersions`
- **Type:** Unary RPC

## Request Parameters

- `package_id` (`string, required`): Storage ID of any package version in the upgrade lineage.
- `page_size` (`uint32, optional`): Maximum items per page. The service may return fewer items.
- `page_token` (`bytes, optional`): Base64 page token from the previous response. Keep other request parameters unchanged.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "package_id": "0x2",
  "page_size": 2
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.MovePackageService/ListPackageVersions
```

## Response Fields

- `versions` (`PackageVersion[], optional`): Package storage IDs and version numbers in version order.
- `next_page_token` (`bytes, optional`): Base64 continuation token. Absent when no further page exists.

## Successful Response

```protobuf
message ListPackageVersionsResponse {
  repeated PackageVersion versions = 1;
  optional bytes next_page_token = 2;
}
```

## Usage notes

Pass `next_page_token` back as `page_token` without changing the package ID or page size.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetCheckpointObjectProof - Verify Sui Object Changes

# GetCheckpointObjectProof - Verify Sui Object Changes

Retrieve a v2alpha cryptographic proof showing whether a Sui checkpoint modified a specific object ID.

## Method Signature

- **Service:** `sui.rpc.v2alpha.ProofService`
- **Method:** `GetCheckpointObjectProof`
- **Type:** Unary RPC

## Request Parameters

- `object_id` (`string, required`): Object ID to prove against the checkpoint's modified-object set.
- `checkpoint` (`uint64, required`): Recent retained checkpoint sequence number for the proof.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "object_id": "0x5",
  "checkpoint": "RECENT_CHECKPOINT"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2alpha.ProofService/GetCheckpointObjectProof
```

## Response Fields

- `checkpoint_summary` (`bytes, optional`): BCS-encoded certified checkpoint summary.
- `inclusion` (`OcsInclusionProof, optional`): Object inclusion proof. Mutually exclusive with non_inclusion.
- `non_inclusion` (`OcsNonInclusionProof, optional`): Object non-inclusion proof. Mutually exclusive with inclusion.

## Successful Response

```protobuf
message GetCheckpointObjectProofResponse {
  optional bytes checkpoint_summary = 1;
  oneof proof {
    OcsInclusionProof inclusion = 2;
    OcsNonInclusionProof non_inclusion = 3;
  }
}
```

## Error Responses

### Checkpoint unavailable

- Code: `NOT_FOUND`
- Description: The checkpoint was pruned or is not yet indexed. Choose a recent checkpoint returned by GetServiceInfo.

## Usage notes

Replace `RECENT_CHECKPOINT` with a recent `checkpointHeight` from [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). The response contains either an inclusion or non-inclusion proof. This experimental API can change.

Historical data is limited by node retention. Check `lowest_available_checkpoint` and `lowest_available_checkpoint_objects` with [GetServiceInfo](https://www.dwellir.com/docs/sui/grpc/ledger/get-service-info). Use an archival source when data has been pruned.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## VerifySignature - Validate Transaction Signatures

# VerifySignature - Validate Transaction Signatures

Verify cryptographic signatures for Sui transactions via gRPC. Essential for security validation and multi-sig workflows with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.SignatureVerificationService`
- **Method:** `VerifySignature`
- **Type:** Unary RPC

## Request Parameters

- `message` (`Bcs, required`): BCS message with name PersonalMessage or TransactionData and base64 value bytes.
- `signature` (`UserSignature, required`): Serialized UserSignature in bcs.value, or the corresponding structured signature.
- `address` (`string, optional`): Optional Sui address that must match the address derived from the signature.
- `jwks` (`ActiveJwk[], optional`): JSON Web Keys for zkLogin verification. Omit to use the current on-chain keys.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "message": {
    "name": "PersonalMessage",
    "value": "GER3ZWxsaXIgU3VpIGdSUEMgZXhhbXBsZQ=="
  },
  "signature": {
    "bcs": {
      "value": "AE1WQkAxmaiLPrnh+Tma40i8dhwTdpEXVI5fehEhGAJFi7aqRGFNQeUd/5jR1g3nIXShY5X35lE4/ryTKthmfguBkTZzhAJETw5HLMkxew8Vmj2YNOsqTyJjxXBkqjHD8g=="
    }
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.SignatureVerificationService/VerifySignature
```

## Response Fields

- `is_valid` (`bool, optional`): Whether the signature verifies against the message and optional address.
- `reason` (`string, optional`): Failure reason when is_valid is false.

## Successful Response

```protobuf
message VerifySignatureResponse {
  optional bool is_valid = 1;
  optional string reason = 2;
}
```

## Usage notes

The example verifies a public, signed personal message. It contains no private key. `message.name` selects the signature intent. A signature mismatch returns `is_valid: false` with `reason`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetBalance - Query Coin Balances via gRPC

# GetBalance - Query Coin Balances via gRPC

Query Sui coin balances efficiently using the gRPC GetBalance method. Check SUI and custom token balances with high-performance binary serialization through Dwellir's Sui infrastructure.

## Method Signature

- **Service:** `sui.rpc.v2.StateService`
- **Method:** `GetBalance`
- **Type:** Unary RPC

## Request Parameters

- `owner` (`string, required`): Sui account address.
- `coin_type` (`string, required`): Move coin type, for example 0x2::sui::SUI.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "owner": "0x0",
  "coin_type": "0x2::sui::SUI"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.StateService/GetBalance
```

## Response Fields

- `balance` (`Balance, optional`): Balance object containing coin_type, balance, address_balance, and coin_balance.

## Successful Response

```protobuf
message GetBalanceResponse {
  optional Balance balance = 1;
}
```

## Usage notes

The response contains a nested `balance` object. Its total is `balance.balance`; `address_balance` and `coin_balance` provide the two components.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## GetCoinInfo - Query Coin Metadata

# GetCoinInfo - Query Coin Metadata

Retrieve comprehensive metadata for Sui coin types including name, symbol, decimals, and supply information via gRPC. Essential for token displays and DeFi applications with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.StateService`
- **Method:** `GetCoinInfo`
- **Type:** Unary RPC

## Request Parameters

- `coin_type` (`string, required`): Move coin type, for example 0x2::sui::SUI.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "coin_type": "0x2::sui::SUI"
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.StateService/GetCoinInfo
```

## Response Fields

- `coin_type` (`string, optional`): Move coin type, for example 0x2::sui::SUI.
- `metadata` (`CoinMetadata, optional`): Coin name, symbol, description, and decimals.
- `treasury` (`CoinTreasury, optional`): Coin treasury, including total_supply.
- `regulated_metadata` (`RegulatedCoinMetadata, optional`): Regulated coin metadata, when present.

## Successful Response

```protobuf
message GetCoinInfoResponse {
  optional string coin_type = 1;
  optional CoinMetadata metadata = 2;
  optional CoinTreasury treasury = 3;
  optional RegulatedCoinMetadata regulated_metadata = 4;
}
```

## Usage notes

Read metadata from `metadata` and supply information from `treasury.total_supply`. Treasury and regulated metadata can be absent.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## ListBalances - Query All Token Balances

# ListBalances - Query All Token Balances

Retrieve all token balances for a Sui address via gRPC including multiple coin types. Essential for portfolio displays and multi-token wallets with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.StateService`
- **Method:** `ListBalances`
- **Type:** Unary RPC

## Request Parameters

- `owner` (`string, required`): Sui account address.
- `page_size` (`uint32, optional`): Maximum items per page. The service may return fewer items.
- `page_token` (`bytes, optional`): Base64 page token from the previous response. Keep other request parameters unchanged.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "owner": "0x0",
  "page_size": 2
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.StateService/ListBalances
```

## Response Fields

- `balances` (`Balance[], optional`): Coin balances for the owner.
- `next_page_token` (`bytes, optional`): Base64 continuation token. Absent when no further page exists.

## Successful Response

```protobuf
message ListBalancesResponse {
  repeated Balance balances = 1;
  optional bytes next_page_token = 2;
}
```

## Usage notes

The response contains `balances`, not `result`. Continue with `next_page_token` while keeping the owner and page size unchanged.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## ListDynamicFields - Query Object Dynamic Fields

# ListDynamicFields - Query Object Dynamic Fields

Retrieve dynamic fields attached to Sui objects via gRPC with pagination support. Essential for exploring extensible objects and collections with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.StateService`
- **Method:** `ListDynamicFields`
- **Type:** Unary RPC

## Request Parameters

- `parent` (`string, required`): Parent object ID containing the dynamic fields.
- `page_size` (`uint32, optional`): Maximum items per page. The service may return fewer items.
- `page_token` (`bytes, optional`): Base64 page token from the previous response. Keep other request parameters unchanged.
- `read_mask` (`FieldMask, optional`): Fields of DynamicField to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "parent": "0x5",
  "page_size": 2
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.StateService/ListDynamicFields
```

## Response Fields

- `dynamic_fields` (`DynamicField[], optional`): Dynamic field entries owned by the parent.
- `next_page_token` (`bytes, optional`): Base64 continuation token. Absent when no further page exists.

## Successful Response

```protobuf
message ListDynamicFieldsResponse {
  repeated DynamicField dynamic_fields = 1;
  optional bytes next_page_token = 2;
}
```

## Usage notes

Use `parent` and `page_size`. The response contains `dynamic_fields` and an optional `next_page_token`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## ListOwnedObjects - Discover Address Assets

# ListOwnedObjects - Discover Address Assets

Query all objects owned by a Sui address via gRPC with pagination support. Essential for wallet interfaces, portfolio tracking, and asset discovery with Dwellir's infrastructure.

## Method Signature

- **Service:** `sui.rpc.v2.StateService`
- **Method:** `ListOwnedObjects`
- **Type:** Unary RPC

## Request Parameters

- `owner` (`string, required`): Sui account address.
- `page_size` (`uint32, optional`): Maximum items per page. The service may return fewer items.
- `page_token` (`bytes, optional`): Base64 page token from the previous response. Keep other request parameters unchanged.
- `read_mask` (`FieldMask, optional`): Fields of Object to return. Use paths relative to that message.
- `object_type` (`string, optional`): Object type filter. SUI coins use 0x2::coin::Coin<0x2::sui::SUI>.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "owner": "0x0",
  "page_size": 2,
  "read_mask": {
    "paths": [
      "object_id",
      "object_type"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.StateService/ListOwnedObjects
```

## Response Fields

- `objects` (`Object[], optional`): Objects currently owned by the requested address.
- `next_page_token` (`bytes, optional`): Base64 continuation token. Absent when no further page exists.

## Successful Response

```protobuf
message ListOwnedObjectsResponse {
  repeated Object objects = 1;
  optional bytes next_page_token = 2;
}
```

## Usage notes

For SUI coins, set `object_type` to `0x2::coin::Coin<0x2::sui::SUI>`. Do not pass the coin type alone. Keep request parameters unchanged when using `page_token`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## SimulateTransaction - Preview Transaction Effects

# SimulateTransaction - Preview Transaction Effects

Simulate Sui transactions before execution to preview effects, gas costs, and potential errors via gRPC. Essential for safe transaction building with Dwellir.

## Method Signature

- **Service:** `sui.rpc.v2.TransactionExecutionService`
- **Method:** `SimulateTransaction`
- **Type:** Unary RPC

## Request Parameters

- `transaction` (`Transaction, required`): Transaction message. Put serialized TransactionData bytes in bcs.value.
- `read_mask` (`FieldMask, optional`): Fields of SimulateTransactionResponse to return. Use paths relative to that message.
- `checks` (`TransactionChecks, optional`): Transaction validation mode. Defaults to ENABLED; DISABLED is for inspection.
- `do_gas_selection` (`bool, optional`): Select gas and estimate a budget when checks are enabled.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "transaction": {
    "bcs": {
      "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AMAAAAAAAAA4fUFAAAAAAA="
    }
  },
  "checks": "DISABLED",
  "read_mask": {
    "paths": [
      "transaction.effects.status",
      "transaction.digest",
      "transaction.effects.gas_used"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.TransactionExecutionService/SimulateTransaction
```

## Response Fields

- `transaction` (`ExecutedTransaction, optional`): Executed transaction data, wrapped in the response.
- `command_outputs` (`CommandResult[], optional`): Intermediate return values and mutated references from simulation.
- `suggested_gas_price` (`uint64, optional`): Suggested gas price above the reference gas price.

## Successful Response

```protobuf
message SimulateTransactionResponse {
  optional ExecutedTransaction transaction = 1;
  repeated CommandResult command_outputs = 2;
  optional uint64 suggested_gas_price = 3;
}
```

## Usage notes

The example uses a synthetic empty transaction with `checks: DISABLED` for inspection. It does not submit a transaction. Use the default `ENABLED` checks when assessing execution validity. Put BCS bytes in `transaction.bcs.value`. Response masks start with `transaction`, for example `transaction.effects.status`.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## SubscribeCheckpoints - Real-Time Checkpoint Streaming

# SubscribeCheckpoints - Real-Time Checkpoint Streaming

## Stream Finalized Sui Checkpoints

`SubscriptionService.SubscribeCheckpoints` is a server-streaming RPC that
delivers finalized Sui checkpoints without polling. When a subscription starts,
the server begins with its latest executed checkpoint. While the connection is
active, unfiltered responses arrive in order and without gaps.

The optional `filter` is a `TransactionFilter`. A checkpoint matches if any transaction it contains satisfies that filter. Matching checkpoint payloads can include nonmatching transactions.

Filtered subscriptions can emit progress-only frames containing `cursor` without `checkpoint`. Advance covered progress only after processing all earlier matching items.

## Method Signature

- **Service**: `sui.rpc.v2.SubscriptionService`
- **Method**: `SubscribeCheckpoints`
- **Type**: Server-streaming RPC

## Request Parameters

- `read_mask` (`FieldMask, optional`): Fields of Checkpoint to return. Use paths relative to that message.
- `filter` (`TransactionFilter, optional`): Optional server-side filter. An included filter must contain at least one term.

## Request Example

```typescript
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

const ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com:443';
const API_TOKEN = 'your_api_token_here';

const packageDefinition = protoLoader.loadSync(
  './protos/sui/rpc/v2/subscription_service.proto',
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: ['./protos']
  }
);

const descriptor = grpc.loadPackageDefinition(packageDefinition) as any;
const client = new descriptor.sui.rpc.v2.SubscriptionService(
  ENDPOINT,
  grpc.credentials.createSsl()
);

const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);

const request = {
  read_mask: {
    paths: [
      'sequence_number',
      'digest',
      'summary.timestamp',
      'transactions.digest'
    ]
  }
};

let lastCursor: bigint | undefined;
let processing = Promise.resolve();
const stream = client.SubscribeCheckpoints(request, metadata);

// Abbreviated skeleton: this promise chain preserves order but is an
// unbounded queue. Add bounded backpressure and the reconnect/backfill
// sequence from the guide before using it in a lossless pipeline.
stream.on('data', (response: any) => {
  processing = processing.then(() => handleCheckpoint(response)).catch((error) => {
    console.error('Checkpoint processing failed:', error);
  });
});

async function handleCheckpoint(response: any) {
  const cursor = BigInt(response.cursor);
  const checkpoint = response.checkpoint;
  if (!checkpoint) return;

  if (lastCursor !== undefined && cursor <= lastCursor) {
    console.log('Skipping duplicate or stale checkpoint', response.cursor);
    return;
  }
  if (lastCursor !== undefined && cursor > lastCursor + 1n) {
    reportCheckpointGap(lastCursor + 1n, cursor - 1n);
    return;
  }

  lastCursor = cursor;
  console.log({
    cursor: response.cursor,
    sequenceNumber: checkpoint.sequence_number,
    digest: checkpoint.digest,
    timestamp: checkpoint.summary?.timestamp
  });
}

stream.on('error', (error: grpc.ServiceError) => {
  console.error('Stream failed:', error.message);
  // Reconnect and historical backfill are intentionally omitted here.
});

function reportCheckpointGap(first: bigint, last: bigint) {
  console.warn(
    `Gap detected: backfill checkpoints ${first} through ${last} before continuing`
  );
}
```

## Response Fields

- `cursor` (`uint64, optional`): Checkpoint position fully covered by this stream.
- `checkpoint` (`Checkpoint, optional`): Checkpoint data. Filtered progress frames can omit this field.

## Successful Response

```protobuf
message SubscribeCheckpointsResponse {
  optional uint64 cursor = 1;
  optional Checkpoint checkpoint = 2;
}
```

The generated language examples are abbreviated gap-detection skeletons. They
show the request and response shapes, but intentionally omit a production
reconnect loop, historical fetch implementation, and bounded backpressure.
Follow [Recover After a Disconnect](#recover-after-a-disconnect) before using
them in a lossless pipeline. Generate all Sui v2 client stubs with the
[language-specific setup](https://www.dwellir.com/docs/sui/grpc-overview#language-specific-setup)
before running the Python example.

The request has two optional fields:

```proto
message SubscribeCheckpointsRequest {
  optional google.protobuf.FieldMask read_mask = 1;
  optional TransactionFilter filter = 2;
}
```

Each streamed response wraps the selected checkpoint data with a cursor:

```proto
message SubscribeCheckpointsResponse {
  optional uint64 cursor = 1;
  optional Checkpoint checkpoint = 2;
}
```

The cursor identifies the checkpoint position in the live stream. It is useful
for detecting gaps and deciding where a historical backfill must begin, but it
is not a resume cursor that can be supplied to a new subscription.

## Choose a Field Mask

A field mask controls response shape, not stream selection. Every active
unfiltered subscription receives one response for every checkpoint. Use `filter` to select matching checkpoints.

| Monitoring goal               | Suggested checkpoint field paths                              |
| ----------------------------- | ------------------------------------------------------------- |
| Checkpoint identity and time  | `sequence_number`, `digest`, `summary.timestamp`              |
| Transaction confirmation      | `transactions.digest`                                         |
| Transactions sent by a wallet | `transactions.digest`, `transactions.transaction.sender`      |
| Wallet balance changes        | `transactions.digest`, `transactions.balance_changes`         |
| Move calls                    | `transactions.digest`, `transactions.transaction.kind`        |
| Emitted events                | `transactions.digest`, `transactions.events.events`           |
| Changed object owners         | `transactions.digest`, `transactions.effects.changed_objects` |

Tracking every way a wallet can be affected usually requires more than the
transaction sender. Include balance changes and changed-object ownership when
you need incoming transfers, object mutations, or other indirect effects.

## Subscribe with TypeScript

This unfiltered example requests checkpoint identity, timestamp, transaction senders,
balance changes, Move commands, and events. It serializes processing, preserves
the last successfully processed cursor, and stops live processing when it finds
a gap. Add bounded storage for the illustrated buffer in production.

```typescript
const request = {
  read_mask: {
    paths: [
      'sequence_number',
      'digest',
      'summary.timestamp',
      'transactions.digest',
      'transactions.transaction.sender',
      'transactions.transaction.kind',
      'transactions.balance_changes',
      'transactions.events.events'
    ]
  }
};

let lastProcessedCursor: bigint | undefined;
let recovering = false;
const bufferedResponses = [];
let processing = Promise.resolve();
const stream = client.SubscribeCheckpoints(request, metadata);

stream.on('data', (response) => {
  processing = processing.then(() => handleCheckpoint(response)).catch((error) => {
    console.error('Checkpoint processing failed', error);
  });
});

async function handleCheckpoint(response) {
  if (recovering) {
    bufferedResponses.push(response);
    return;
  }

  const checkpoint = response.checkpoint;
  if (!checkpoint) return;

  const cursor = BigInt(response.cursor);
  if (lastProcessedCursor !== undefined && cursor <= lastProcessedCursor) {
    console.log('Skipping duplicate or stale checkpoint', response.cursor);
    return;
  }
  if (lastProcessedCursor !== undefined && cursor > lastProcessedCursor + 1n) {
    recovering = true;
    bufferedResponses.push(response);
    console.warn('Checkpoint gap detected', {
      firstMissing: (lastProcessedCursor + 1n).toString(),
      lastMissing: (cursor - 1n).toString()
    });
    // Run the recovery sequence below, then drain bufferedResponses in cursor
    // order before clearing recovering.
    return;
  }

  console.log('Checkpoint received', {
    cursor: response.cursor,
    sequenceNumber: checkpoint.sequence_number,
    digest: checkpoint.digest,
    timestamp: checkpoint.summary?.timestamp,
    transactionCount: checkpoint.transactions?.length ?? 0
  });

  await processMatchingTransactions(checkpoint);
  lastProcessedCursor = cursor;
}

stream.on('error', (error) => {
  console.error('Checkpoint stream failed', {
    code: error.code,
    message: error.message,
    lastProcessedCursor: lastProcessedCursor?.toString()
  });
});
```

Generated clients can expose protobuf field names differently. The examples on
this page use snake\_case, matching clients configured with `keepCase: true`.

## Filter Transactions Client-Side

Use [server-side filters](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters) for indexed predicates. Apply additional conditions to the transactions inside each returned checkpoint:

```typescript
function normalizeSuiId(value: string | undefined): string {
  if (!value) return '';
  const hex = value.toLowerCase().replace(/^0x/, '');
  return `0x${hex.padStart(64, '0')}`;
}

const watchedAddress = normalizeSuiId('0x...');
const watchedPackage = normalizeSuiId('0x2');
const watchedModule = 'coin';
const watchedEventType = `${watchedPackage}::${watchedModule}::WatchedEvent`;

async function processMatchingTransactions(checkpoint: any): Promise<void> {
  for (const executed of checkpoint.transactions ?? []) {
    const sentByWallet =
      normalizeSuiId(executed.transaction?.sender) === watchedAddress;

    const changedWalletBalance = (executed.balance_changes ?? []).some(
      (change: any) =>
        normalizeSuiId(change.address) === watchedAddress
    );

    const calledWatchedModule = (
      executed.transaction?.kind?.programmable_transaction?.commands ?? []
    ).some((command: any) => {
      const moveCall = command.move_call;
      return (
        normalizeSuiId(moveCall?.package) === watchedPackage &&
        moveCall?.module === watchedModule
      );
    });

    const emittedWatchedEvent = (executed.events?.events ?? []).some(
      (event: any) => {
        const emittedByWatchedModule =
          normalizeSuiId(event.package_id) === watchedPackage &&
          event.module === watchedModule;
        const matchesDeclaredEventType = event.event_type === watchedEventType;
        return emittedByWatchedModule || matchesDeclaredEventType;
      }
    );

    if (sentByWallet || changedWalletBalance || calledWatchedModule || emittedWatchedEvent) {
      await handleMatchingTransaction(executed);
    }
  }
}
```

`event.package_id` and `event.module` identify the top-level Move call that
triggered emission. `event.event_type` identifies the declared event type.
Those packages can differ, so retain only the predicate that matches the
monitoring requirement.

Field masks keep this processing efficient by omitting transaction signatures,
object contents, effects, and other data that the matcher does not need.

## Recover After a Disconnect

A new subscription starts at the latest checkpoint known to the server. It does
not replay from the previous connection's cursor automatically.

The following sequence and the `cursor + 1` gap check apply to the unfiltered examples on this page. They do not apply to a filtered stream, which can skip nonmatching checkpoints.

Use this recovery sequence:

1. Persist the last processed cursor or checkpoint sequence number.
2. Reconnect with exponential backoff.
3. Compare every new cursor with the last processed cursor. Skip a duplicate or
   stale response when `cursor <= lastProcessedCursor`.
4. If `cursor > lastProcessedCursor + 1`, record the missing range and buffer
   the gap-detecting response and every later response. Do not process or
   advance the persisted cursor for any buffered response yet.
5. Call `LedgerService.GetServiceInfo` and inspect
   `lowest_available_checkpoint`. If the first missing checkpoint is still
   retained, fetch each missing checkpoint with
   [`LedgerService.GetCheckpoint`](https://www.dwellir.com/docs/sui/grpc/ledger/get-checkpoint).
6. If the gap predates `lowest_available_checkpoint`, recover from an archival
   endpoint or your own durable checkpoint store instead.
7. Process the backfill in order, then drain buffered live data in cursor order.
   Advance `lastProcessedCursor` only after each downstream operation succeeds.

Do not assume a reconnect is lossless. The in-order, gap-free guarantee applies
to an active subscription, not across separate connections. A retained full
node cannot guarantee lossless recovery after a sufficiently long outage unless
an archival endpoint or durable checkpoint store covers the missing range.

## Recover a filtered subscription

Persist the last fully covered cursor after processing all earlier matching checkpoints. Cursor-only frames advance coverage without carrying a checkpoint.

After reconnecting, buffer live responses. Let `savedCursor` be your persisted position and `firstCursor` be the first buffered response's cursor.

If `firstCursor > savedCursor`, replay the gap with `LedgerService.ListCheckpoints` using the same filter and read mask:

- Set `start_checkpoint` to `savedCursor + 1`.
- Set `end_checkpoint` to `firstCursor + 1`. The end bound is exclusive, so this includes `firstCursor`.
- After each response, process any matching checkpoint before persisting its covered progress.
- Read covered progress from `watermark.checkpoint`. It can be absent before the scan fully covers its first checkpoint.
- For pagination or scan limits, pass the last `watermark.cursor` as `options.after` while preserving the checkpoint bounds.

The historical index can trail the live stream. Repeat scans as indexing advances until `watermark.checkpoint >= firstCursor`; reaching the current indexed tip alone is insufficient.

Then drain buffered responses in cursor order. Skip every response whose cursor is at or below the last covered cursor, including any checkpoint already processed by replay.

Use integer arithmetic for checkpoint cursors. The historical `watermark.cursor` is an opaque continuation token, distinct from `watermark.checkpoint`.

A jump between matching checkpoints does not prove data loss. Track covered progress and deduplicate overlap between replay and the live buffer.

## Operational Guidance

- **Use keepalives** appropriate for your client and network path.
- **Persist progress** only after downstream processing succeeds.
- **Apply backpressure** instead of dropping checkpoints when processing falls
  behind.
- **Request narrow field masks** to reduce serialization work and bandwidth.
- **Regenerate clients** from the current
  [official Sui protobuf definitions](https://github.com/MystenLabs/sui-apis/tree/main/proto/sui/rpc/v2)
  when upgrading API versions.
- **Use paired List methods for retained history**. Use GraphQL or an archival source for queries beyond the node's retention window.

## Related Resources

- [GetCheckpoint](https://www.dwellir.com/docs/sui/grpc/ledger/get-checkpoint) - Backfill a checkpoint by sequence number
- [GetTransaction](https://www.dwellir.com/docs/sui/grpc/ledger/get-transaction) - Retrieve a transaction by digest
- [Sui gRPC documentation](https://docs.sui.io/develop/accessing-data/grpc) - Native Sui concepts and usage
- [Sui subscription protobuf](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/subscription_service.proto) - Authoritative request and response schema

***

*Need help with real-time streaming? Contact our [support team](mailto:support@dwellir.com) or review the [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview).*

---

## SubscribeEvents - Stream Live Sui Events

# SubscribeEvents - Stream Live Sui Events

`SubscriptionService.SubscribeEvents` streams live events from the node's current tip. Use an `EventFilter` for server-side selection and a field mask to control each event payload.

## Method Signature

- **Service:** `sui.rpc.v2.SubscriptionService`
- **Method:** `SubscribeEvents`
- **Type:** Server-streaming RPC

## Request Parameters

- `read_mask` (`FieldMask, optional`): Fields of Event to return. Use paths relative to that message.
- `filter` (`EventFilter, optional`): Optional server-side filter. An included filter must contain at least one term.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "read_mask": {
    "paths": [
      "event_type",
      "transaction_digest",
      "event_index",
      "checkpoint"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.SubscriptionService/SubscribeEvents
```

## Response Fields

- `event` (`Event, optional`): Requested event.
- `watermark` (`Watermark, optional`): Progress and continuation cursor. Present even when a frame contains no matching item.

## Successful Response

```protobuf
message SubscribeEventsResponse {
  optional Event event = 1;
  optional Watermark watermark = 2;
}
```

## Recover after a disconnect

Subscriptions do not resume automatically. Persist `watermark.cursor` only after processing all earlier matching items.

For event recovery, request both `transaction_digest` and `event_index` in the subscription and replay masks.

After reconnecting, buffer live responses. Let `firstCursor` be the first buffered frame's `watermark.cursor` and keep it fixed during replay.

Call [ListEvents](https://www.dwellir.com/docs/sui/grpc/ledger/list-events) with the same filter and read mask:

- Set `options.after` to the saved, fully processed `watermark.cursor`.
- Set `options.before` to `firstCursor`.
- Set `options.limit` to the desired page size.
- Omit `start_checkpoint` and `end_checkpoint` for this cursor-bounded replay.

Process each returned item before advancing saved progress. Inspect the terminal frame's `end.reason`:

| End reason                                                     | Action                                                                                                                                   |
| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `QUERY_END_REASON_ITEM_LIMIT` or `QUERY_END_REASON_SCAN_LIMIT` | Set `options.after` to the terminal `watermark.cursor` and fetch the next page. Keep `options.before` fixed.                             |
| `QUERY_END_REASON_LEDGER_TIP`                                  | The index trails the live boundary. Resume from the terminal `watermark.cursor` after indexing advances, with the same `options.before`. |
| `QUERY_END_REASON_CURSOR_BOUND`                                | Replay reached the requested boundary. Drain the buffered live responses.                                                                |

Other end reasons and RPC errors do not establish completion. Resume from the last fully processed progress after addressing the error.

Use `end.reason` for completion; `watermark.checkpoint` can lag at a cursor boundary. Cursors are opaque base64 tokens, so preserve them without arithmetic or lexical comparison.

Deduplicate replay and buffered data by transaction digest and event index before applying downstream effects. Persist progress-only watermarks only after all earlier matching items have been processed.

Recovery beyond the node's retained history requires an archival source or a durable local store.

## Related Methods

- [ListEvents](https://www.dwellir.com/docs/sui/grpc/ledger/list-events)
- [SubscribeTransactions](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-transactions)
- [SubscribeCheckpoints](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-checkpoints)

See the [official Sui gRPC schema](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/subscription_service.proto) for the current protobuf definition.

See [filter syntax and examples](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters). Filtered subscriptions can send progress-only frames with no item. Persist their watermark after processing all earlier items.

---

## SubscribeTransactions - Stream Live Sui Transactions

# SubscribeTransactions - Stream Live Sui Transactions

`SubscriptionService.SubscribeTransactions` streams live transactions from the node's current tip. Each frame includes a progress watermark and, when a transaction matches, the transaction payload.

## Method Signature

- **Service:** `sui.rpc.v2.SubscriptionService`
- **Method:** `SubscribeTransactions`
- **Type:** Server-streaming RPC

## Request Parameters

- `read_mask` (`FieldMask, optional`): Fields of ExecutedTransaction to return. Use paths relative to that message.
- `filter` (`TransactionFilter, optional`): Optional server-side filter. An included filter must contain at least one term.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "read_mask": {
    "paths": [
      "digest"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.SubscriptionService/SubscribeTransactions
```

## Response Fields

- `transaction` (`ExecutedTransaction, optional`): Executed transaction data, wrapped in the response.
- `watermark` (`Watermark, optional`): Progress and continuation cursor. Present even when a frame contains no matching item.

## Successful Response

```protobuf
message SubscribeTransactionsResponse {
  optional ExecutedTransaction transaction = 1;
  optional Watermark watermark = 2;
}
```

## Recover after a disconnect

Subscriptions do not resume automatically. Persist `watermark.cursor` only after processing all earlier matching items.

For transaction recovery, request `digest` in both masks.

After reconnecting, buffer live responses. Let `firstCursor` be the first buffered frame's `watermark.cursor` and keep it fixed during replay.

Call [ListTransactions](https://www.dwellir.com/docs/sui/grpc/ledger/list-transactions) with the same filter and read mask:

- Set `options.after` to the saved, fully processed `watermark.cursor`.
- Set `options.before` to `firstCursor`.
- Set `options.limit` to the desired page size.
- Omit `start_checkpoint` and `end_checkpoint` for this cursor-bounded replay.

Process each returned item before advancing saved progress. Inspect the terminal frame's `end.reason`:

| End reason                                                     | Action                                                                                                                                   |
| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `QUERY_END_REASON_ITEM_LIMIT` or `QUERY_END_REASON_SCAN_LIMIT` | Set `options.after` to the terminal `watermark.cursor` and fetch the next page. Keep `options.before` fixed.                             |
| `QUERY_END_REASON_LEDGER_TIP`                                  | The index trails the live boundary. Resume from the terminal `watermark.cursor` after indexing advances, with the same `options.before`. |
| `QUERY_END_REASON_CURSOR_BOUND`                                | Replay reached the requested boundary. Drain the buffered live responses.                                                                |

Other end reasons and RPC errors do not establish completion. Resume from the last fully processed progress after addressing the error.

Use `end.reason` for completion; `watermark.checkpoint` can lag at a cursor boundary. Cursors are opaque base64 tokens, so preserve them without arithmetic or lexical comparison.

Deduplicate replay and buffered data by transaction digest before applying downstream effects. Persist progress-only watermarks only after all earlier matching items have been processed.

Recovery beyond the node's retained history requires an archival source or a durable local store.

## Related Methods

- [ListTransactions](https://www.dwellir.com/docs/sui/grpc/ledger/list-transactions)
- [GetTransaction](https://www.dwellir.com/docs/sui/grpc/ledger/get-transaction)
- [SubscribeEvents](https://www.dwellir.com/docs/sui/grpc/subscription/subscribe-events)

See the [official Sui gRPC schema](https://github.com/MystenLabs/sui-apis/blob/main/proto/sui/rpc/v2/subscription_service.proto) for the current protobuf definition.

See [filter syntax and examples](https://www.dwellir.com/docs/sui/grpc-overview#server-side-filters). Filtered subscriptions can send progress-only frames with no item. Persist their watermark after processing all earlier items.

---

## ExecuteTransaction - Submit Signed Transactions

# ExecuteTransaction - Submit Signed Transactions

Execute signed transactions on Sui blockchain via gRPC. Learn how to submit transactions, handle signatures, and verify execution with Dwellir's high-performance infrastructure.

## Method Signature

- **Service:** `sui.rpc.v2.TransactionExecutionService`
- **Method:** `ExecuteTransaction`
- **Type:** Unary RPC

## Request Parameters

- `transaction` (`Transaction, required`): Transaction message. Put serialized TransactionData bytes in bcs.value.
- `signatures` (`UserSignature[], required`): Signatures authorizing this transaction. Each serialized UserSignature belongs in bcs.value.
- `read_mask` (`FieldMask, optional`): Fields of ExecutedTransaction to return. Use paths relative to that message.

## Request Example

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
  "transaction": {
    "bcs": {
      "value": "BASE64_TRANSACTION_BCS"
    }
  },
  "signatures": [
    {
      "bcs": {
        "value": "BASE64_SERIALIZED_SIGNATURE"
      }
    }
  ],
  "read_mask": {
    "paths": [
      "digest",
      "effects.status"
    ]
  }
}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.TransactionExecutionService/ExecuteTransaction
```

## Response Fields

- `transaction` (`ExecutedTransaction, optional`): Executed transaction data, wrapped in the response.

## Successful Response

```protobuf
message ExecuteTransactionResponse {
  optional ExecutedTransaction transaction = 1;
}
```

## Usage notes

Replace both base64 placeholders with transaction bytes and the serialized signature from your Sui SDK. Do not use a personal-message signature. The service is `TransactionExecutionService`. Read masks refer to the nested `ExecutedTransaction`, so use `effects.status` or `digest`. Successful submission changes on-chain state.

## Related resources

- [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview)
- [grpcurl setup](https://www.dwellir.com/docs/sui/grpc-setup-grpcurl)

---

## Sui JSON-RPC Removal and Migration Guide

# Sui JSON-RPC Removal and Migration Guide

Sui removed the JSON-RPC service from full nodes in `mainnet-v1.82.3`. Dwellir's Sui full-node endpoint now uses gRPC for live node access, transaction execution, historical scans within the node's retention window, and real-time streams.

Applications that call Sui JSON-RPC methods must migrate to gRPC or GraphQL. Changing only the URL does not work because the request and response schemas differ.

## Official Timeline

Sui disabled JSON-RPC on Sui Foundation mainnet full nodes during the week of July 27, 2026. The remaining infrastructure was scheduled for full decommission, including code removal, in mid-October 2026.

- [Sui mainnet-v1.82.3 release](https://github.com/MystenLabs/sui/releases/tag/mainnet-v1.82.3)
- [Official JSON-RPC migration guide](https://docs.sui.io/develop/accessing-data/json-rpc-migration)
- [Sui gRPC documentation](https://docs.sui.io/develop/accessing-data/grpc)

## Choose gRPC or GraphQL

Use gRPC for transaction execution, recent ledger data, current state, typed clients, and live checkpoint, transaction, or event streams. Use GraphQL for joined queries, flexible filtering, and historical data beyond a full node's retention window.

| Retired JSON-RPC method          | gRPC replacement                                                                                                                              | GraphQL guidance                                       |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `sui_getCheckpoint`              | [`LedgerService.GetCheckpoint`](https://www.dwellir.com/docs/sui/grpc/ledger/get-checkpoint)                                                                         | `Query.checkpoint`                                     |
| `sui_getTransactionBlock`        | [`LedgerService.GetTransaction`](https://www.dwellir.com/docs/sui/grpc/ledger/get-transaction)                                                                       | `Query.transaction`                                    |
| `sui_multiGetTransactionBlocks`  | [`LedgerService.BatchGetTransactions`](https://www.dwellir.com/docs/sui/grpc/ledger/batch-get-transactions)                                                          | `Query.multiGetTransactions`                           |
| `sui_getObject`                  | [`LedgerService.GetObject`](https://www.dwellir.com/docs/sui/grpc/ledger/get-object)                                                                                 | `Query.object`                                         |
| `sui_multiGetObjects`            | [`LedgerService.BatchGetObjects`](https://www.dwellir.com/docs/sui/grpc/ledger/batch-get-objects)                                                                    | `Query.multiGetObjects`                                |
| `suix_getBalance`                | [`StateService.GetBalance`](https://www.dwellir.com/docs/sui/grpc/state/get-balance)                                                                                 | `Address.balance`                                      |
| `suix_getAllBalances`            | [`StateService.ListBalances`](https://www.dwellir.com/docs/sui/grpc/state/list-balances)                                                                             | `Address.balances`                                     |
| `suix_getCoins`                  | [`StateService.ListOwnedObjects`](https://www.dwellir.com/docs/sui/grpc/state/list-owned-objects) with `object_type: "0x2::coin::Coin<T>"` for coin type `T`         | `Address.objects`                                      |
| `suix_getDynamicFields`          | [`StateService.ListDynamicFields`](https://www.dwellir.com/docs/sui/grpc/state/list-dynamic-fields)                                                                  | `Object.dynamicFields`                                 |
| `suix_queryTransactionBlocks`    | [`LedgerService.ListTransactions`](https://www.dwellir.com/docs/sui/grpc/ledger/list-transactions)                                                                   | `Query.transactions`                                   |
| `suix_queryEvents`               | [`LedgerService.ListEvents`](https://www.dwellir.com/docs/sui/grpc/ledger/list-events)                                                                               | `Query.events`                                         |
| `sui_executeTransactionBlock`    | [`TransactionExecutionService.ExecuteTransaction`](https://www.dwellir.com/docs/sui/grpc/transaction/execute)                                                        | `Mutation.executeTransaction`                          |
| `sui_dryRunTransactionBlock`     | [`TransactionExecutionService.SimulateTransaction`](https://www.dwellir.com/docs/sui/grpc/state/simulate-transaction)                                                | `Query.simulateTransaction`                            |
| `sui_devInspectTransactionBlock` | [`TransactionExecutionService.SimulateTransaction`](https://www.dwellir.com/docs/sui/grpc/state/simulate-transaction), with `checks: DISABLED` and `command_outputs` | Use GraphQL simulation for equivalent inspection needs |
| `suix_getCoinMetadata`           | [`StateService.GetCoinInfo`](https://www.dwellir.com/docs/sui/grpc/state/get-coin-info), read `metadata`                                                             | Coin metadata queries                                  |
| `suix_getCommitteeInfo`          | [`LedgerService.GetEpoch`](https://www.dwellir.com/docs/sui/grpc/ledger/get-epoch), read `epoch.committee`                                                           | Epoch validator membership                             |
| `suix_getLatestSuiSystemState`   | [`LedgerService.GetEpoch`](https://www.dwellir.com/docs/sui/grpc/ledger/get-epoch), read `epoch.system_state`                                                        | Current epoch system state                             |
| `suix_getOwnedObjects`           | [`StateService.ListOwnedObjects`](https://www.dwellir.com/docs/sui/grpc/state/list-owned-objects)                                                                    | Use GraphQL for unsupported object filters             |
| `suix_getReferenceGasPrice`      | [`LedgerService.GetEpoch`](https://www.dwellir.com/docs/sui/grpc/ledger/get-epoch), read `epoch.reference_gas_price`                                                 | Current epoch gas price                                |
| `suix_getTotalSupply`            | [`StateService.GetCoinInfo`](https://www.dwellir.com/docs/sui/grpc/state/get-coin-info), read `treasury.total_supply`                                                | Coin supply queries                                    |
| `suix_getStakes`                 | No one-to-one gRPC method; query staking objects and decode their state                                                                       | Follow the official staking migration guidance         |
| `suix_getValidatorsApy`          | No direct full-node APY method; calculate from epoch data or use an indexer                                                                   | Follow the official validator APY migration guidance   |

The [official migration guide](https://docs.sui.io/develop/accessing-data/json-rpc-migration) covers staking, validator APY, normalized Move metadata, and transaction builders. Some replacements require additional decoding or computation.

## Connect to Dwellir gRPC

Use TLS on port 443 and send the API key as metadata:

```bash
grpcurl \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{}' \
  api-sui-mainnet-full.n.dwellir.com:443 \
  sui.rpc.v2.LedgerService/GetServiceInfo
```

Continue with the [Sui gRPC overview](https://www.dwellir.com/docs/sui/grpc-overview) or open the [complete gRPC method reference](https://www.dwellir.com/docs/sui#api-reference).

---

## Taiko RPC documentation

# Taiko RPC documentation

## Taiko RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Taiko supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Build on Taiko

Taiko is an Ethereum-equivalent based rollup. Its JSON-RPC interface works with Ethereum libraries and tools. Dwellir provides archive access for historical state queries.

## Connect to Taiko mainnet

Replace `YOUR_API_KEY` with your Dwellir API key. Both transports use the root path after the key.

### Check the chain ID

cURL
Ethers.js v6

```bash
curl -X POST 'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'
);
const network = await provider.getNetwork();
console.log(network.chainId === 167000n);
```

The `eth_chainId` result is `0x28c58`, or **167000** in decimal.

### Subscribe to new blocks

Connect to `wss://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY`. Send this JSON-RPC request:

```json
{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
```

The response contains a subscription ID. Subsequent `eth_subscription` messages contain new block headers.

## Network specifications

| Parameter     | Value              |
| ------------- | ------------------ |
| Chain ID      | 167000 (`0x28c58`) |
| Network       | Taiko mainnet      |
| Node client   | Reth               |
| Node type     | Archive            |
| RPC transport | HTTPS and WSS      |

## API reference

The reference lists standard EVM methods for Taiko. The endpoint also returned results for historical balances, transaction receipts, event logs, `debug_traceTransaction`, and `trace_transaction` in direct checks.

## Resources

- [Taiko network](https://www.dwellir.com/networks/taiko)
- [Top Taiko RPC providers compared](https://www.dwellir.com/blog/top-taiko-rpc-providers)
- [Authentication](https://www.dwellir.com/docs/getting-started/authentication)
- [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)
- [Taiko documentation](https://docs.taiko.xyz/)

---

## debug_traceBlock - Taiko RPC Method

# debug_traceBlock - Taiko RPC Method

Traces all transactions in a block on Taiko by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Taiko - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for Taiko developers:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Taiko
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for Taiko mainnet
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Taiko:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Taiko blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/taiko/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/taiko/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/taiko/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/taiko/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Taiko RPC Method

# debug_traceBlockByHash - Taiko RPC Method

Traces all transactions in a block on Taiko identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Taiko - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for Taiko developers:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Taiko
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for Taiko mainnet
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Taiko:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Taiko:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/taiko/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/taiko/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/taiko/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/taiko/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/taiko/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Taiko RPC Method

# debug_traceBlockByNumber - Taiko RPC Method

Traces all transactions in a block on Taiko identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Taiko - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for Taiko developers:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Taiko execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for Taiko mainnet
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Taiko:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Taiko:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/taiko/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/taiko/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/taiko/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/taiko/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Taiko RPC Method

# debug_traceCall - Taiko RPC Method

Traces a call on Taiko without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Taiko - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for Taiko developers:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Taiko
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for Taiko mainnet
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x1670000000000000000000000000000000010001",
      "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x1670000000000000000000000000000000010001",
        "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x1670000000000000000000000000000000010001",
        "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x1670000000000000000000000000000000010001',
    data: '0x70a082310000000000000000000000001670000000000000000000000000000000010001'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x1670000000000000000000000000000000010001',
    data: '0x70a082310000000000000000000000001670000000000000000000000000000000010001'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x1670000000000000000000000000000000010001',
    'data': '0x70a082310000000000000000000000001670000000000000000000000000000000010001'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x1670000000000000000000000000000000010001",
        "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Taiko to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Taiko:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Taiko:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x1670000000000000000000000000000000010001',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/taiko/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/taiko/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/taiko/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/taiko/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/taiko/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Taiko RPC Method

# debug_traceTransaction - Taiko RPC Method

Traces a transaction execution on Taiko by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for Taiko mainnet
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Taiko
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/taiko/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/taiko/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Taiko RPC Method

# eth_accounts - Taiko RPC Method

Returns a list of addresses owned by the client on Taiko.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for Taiko developers in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/taiko/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/taiko/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Taiko RPC Method

# eth_blockNumber - Taiko RPC Method

Returns the number of the most recent block on Taiko.

## When to Use This Method

`eth_blockNumber` is fundamental for Taiko developers:

- **Syncing Applications** - Keep your dApp in sync with the latest Taiko blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on Taiko mainnet
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Taiko block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Taiko block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Taiko block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Taiko block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Taiko block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Taiko:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Taiko:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Taiko node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/taiko/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/taiko/eth_syncing) - Check if node is still syncing

---

## eth_call - Taiko RPC Method

# eth_call - Taiko RPC Method

Executes a new message call immediately without creating a transaction on Taiko. Used for reading smart contract state.

## When to Use This Method

The `eth_call` method serves these key scenarios for Taiko developers:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Taiko
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on Taiko mainnet

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x1670000000000000000000000000000000010001';
const walletAddress = '0x1670000000000000000000000000000000010001';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Taiko. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x1670000000000000000000000000000000010001';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x1670000000000000000000000000000000010001';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Taiko
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Taiko

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x1670000000000000000000000000000000010001",
      "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x1670000000000000000000000000000000010001",
      "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x1670000000000000000000000000000000010001',
    '0x1670000000000000000000000000000000010001'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")
    data := common.FromHex("0x70a082310000000000000000000000001670000000000000000000000000000000010001")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/taiko/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/taiko/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Taiko RPC Method

# eth_chainId - Taiko RPC Method

Returns the chain ID used for transaction signing on Taiko.

## When to Use This Method

`eth_chainId` is essential for Taiko developers:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on Taiko mainnet

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/taiko/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/taiko/eth_syncing) - Check sync status

---

## eth_estimateGas - Taiko RPC Method

# eth_estimateGas - Taiko RPC Method

Estimates the gas necessary to execute a transaction on Taiko.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for Taiko developers:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for Taiko mainnet
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Taiko
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x1670000000000000000000000000000000010001', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x1670000000000000000000000000000000010001', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Taiko.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Taiko may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x1670000000000000000000000000000000010001',
  '0x1670000000000000000000000000000000010001',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x1670000000000000000000000000000000010001",
    "to": "0x1670000000000000000000000000000000010001",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x1670000000000000000000000000000000010001",
      "to": "0x1670000000000000000000000000000000010001",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x1670000000000000000000000000000000010001', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/taiko/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/taiko/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Taiko RPC Method

# eth_feeHistory - Taiko RPC Method

Returns historical gas fee data on Taiko, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for Taiko developers:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for Taiko mainnet
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Taiko without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Taiko.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Taiko) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/taiko/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/taiko/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/taiko/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Taiko RPC Method

# eth_gasPrice - Taiko RPC Method

Returns the current gas price on Taiko in wei.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for Taiko developers:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Taiko
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Taiko. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Taiko, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Taiko: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Taiko supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/taiko/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/taiko/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/taiko/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Taiko RPC Method

# eth_getBalance - Taiko RPC Method

Returns the balance of a given address on Taiko.

## When to Use This Method

`eth_getBalance` is fundamental for Taiko developers:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Taiko
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Taiko
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across Taiko mainnet
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x1670000000000000000000000000000000010001",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Taiko. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Taiko`);
  return balance;
}

displayBalance('0x1670000000000000000000000000000000010001');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Taiko at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x1670000000000000000000000000000000010001'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Taiko')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Taiko')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Taiko.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x1670000000000000000000000000000000010001")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x1670000000000000000000000000000000010001",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x1670000000000000000000000000000000010001';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x1670000000000000000000000000000000010001'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x1670000000000000000000000000000000010001")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/taiko/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/taiko/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Taiko RPC Method

# eth_getBlockByHash - Taiko RPC Method

Returns information about a block by hash on Taiko.

## When to Use This Method

`eth_getBlockByHash` is essential for Taiko developers:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Taiko
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Taiko's Ethereum-equivalent based rollup
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for Taiko mainnet
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Taiko.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Taiko's Ethereum-equivalent based rollup.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Taiko.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/taiko/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Taiko RPC Method

# eth_getBlockByNumber - Taiko RPC Method

Returns information about a block by block number on Taiko.

## When to Use This Method

`eth_getBlockByNumber` is essential for Taiko developers:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Taiko
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for Taiko mainnet
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Taiko's Ethereum-equivalent based rollup

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Taiko with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Taiko. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Taiko's Ethereum-equivalent based rollup expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/taiko/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/taiko/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/taiko/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Taiko RPC Method

# eth_getBlockReceipts - Taiko RPC Method

Returns all transaction receipts for a block on Taiko. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

## When to Use This Method

`eth_getBlockReceipts` is useful for Taiko developers:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for Taiko mainnet
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Taiko, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Taiko. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Taiko's Ethereum-equivalent based rollup, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x74d9a336a73bd997466824281c94326fa58c89fd201f2ea902e92e1447fe7845",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/taiko/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/taiko/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Taiko RPC Method

# eth_getCode - Taiko RPC Method

Returns the bytecode at a given address on Taiko.

## When to Use This Method

`eth_getCode` is essential for Taiko developers:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Taiko
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on Taiko mainnet

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Taiko:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Taiko:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x1670000000000000000000000000000000010001",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x1670000000000000000000000000000000010001",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x1670000000000000000000000000000000010001';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x1670000000000000000000000000000000010001'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x1670000000000000000000000000000000010001")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/taiko/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/taiko/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Taiko RPC Method

# eth_getFilterChanges - Taiko RPC Method

Polls a filter on Taiko for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

## When to Use This Method

`eth_getFilterChanges` is essential for Taiko developers:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Taiko
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for Taiko mainnet
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x1670000000000000000000000000000000010001',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x1670000000000000000000000000000000010001'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Taiko:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/taiko/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/taiko/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/taiko/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/taiko/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/taiko/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Taiko RPC Method

# eth_getFilterLogs - Taiko RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Taiko. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

## When to Use This Method

`eth_getFilterLogs` is essential for Taiko developers:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Taiko
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x1670000000000000000000000000000000010001"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x1670000000000000000000000000000000010001',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x1670000000000000000000000000000000010001'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/taiko/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/taiko/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/taiko/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/taiko/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Taiko RPC Method

# eth_getLogs - Taiko RPC Method

Returns an array of all logs matching a given filter object on Taiko.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for Taiko developers:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Taiko for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across Taiko mainnet
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Taiko
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x1670000000000000000000000000000000010001';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x1670000000000000000000000000000000010001';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Taiko.

```javascript
const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Taiko enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Taiko, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x1670000000000000000000000000000000010001",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x1670000000000000000000000000000000010001",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x1670000000000000000000000000000000010001",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x1670000000000000000000000000000000010001',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x1670000000000000000000000000000000010001',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/taiko/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/taiko/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Taiko RPC Method

# eth_getStorageAt - Taiko RPC Method

Returns the value from a storage position at a given address on Taiko. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

## When to Use This Method

`eth_getStorageAt` is essential for Taiko 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 Taiko mainnet
- **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": [
    "0x1670000000000000000000000000000000010001",
    "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-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x1670000000000000000000000000000000010001",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x1670000000000000000000000000000000010001', '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-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x1670000000000000000000000000000000010001';

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-taiko-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 = '0x1670000000000000000000000000000000010001'
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-taiko-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-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x1670000000000000000000000000000000010001")
    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 Taiko:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-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-taiko-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 = '0x1670000000000000000000000000000000010001';
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 Taiko:`);
  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/taiko/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/taiko/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/taiko/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Taiko RPC Method

# eth_getTransactionByHash - Taiko RPC Method

Returns the information about a transaction by transaction hash on Taiko.

## When to Use This Method

`eth_getTransactionByHash` is essential for Taiko developers:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Taiko
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for Taiko mainnet
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Taiko's Ethereum-equivalent based rollup

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Taiko. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Taiko. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Taiko's Ethereum-equivalent based rollup.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/taiko/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/taiko/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Taiko RPC Method

# eth_getTransactionCount - Taiko RPC Method

Returns the number of transactions sent from an address on Taiko, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

## When to Use This Method

`eth_getTransactionCount` is essential for Taiko developers:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Taiko
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on Taiko mainnet
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x1670000000000000000000000000000000010001",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x1670000000000000000000000000000000010001",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x1670000000000000000000000000000000010001', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Taiko nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x1670000000000000000000000000000000010001';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x1670000000000000000000000000000000010001'
nonce = get_transaction_count(address)
print(f'Taiko nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x1670000000000000000000000000000000010001")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Taiko nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Taiko:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x1670000000000000000000000000000000010001');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/taiko/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/taiko/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/taiko/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/taiko/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Taiko RPC Method

# eth_getTransactionReceipt - Taiko RPC Method

Returns the receipt of a transaction by transaction hash on Taiko. Receipt is only available for mined transactions.

## When to Use This Method

`eth_getTransactionReceipt` is essential for Taiko developers:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Taiko and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for Taiko mainnet
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Taiko's Ethereum-equivalent based rollup by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Taiko. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Taiko, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Taiko's Ethereum-equivalent based rollup. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Taiko's Ethereum-equivalent based rollup
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/taiko/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/taiko/eth_getLogs) - Query logs by filter

---

## eth_maxPriorityFeePerGas - Taiko RPC Method

# eth_maxPriorityFeePerGas - Taiko RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Taiko. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for Taiko developers:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Taiko
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on Taiko mainnet
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Taiko priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Taiko priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Taiko priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Taiko:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Taiko:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/taiko/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/taiko/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/taiko/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/taiko/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_newBlockFilter - Taiko RPC Method

# eth_newBlockFilter - Taiko RPC Method

Creates a filter on Taiko that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

## When to Use This Method

`eth_newBlockFilter` is essential for Taiko developers:

- **Block Monitoring** - Detect new blocks on Taiko as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Taiko:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/taiko/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/taiko/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/taiko/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/taiko/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Taiko RPC Method

# eth_newFilter - Taiko RPC Method

Creates a filter object on Taiko based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

## When to Use This Method

`eth_newFilter` is essential for Taiko developers:

- **Event Monitoring** - Subscribe to specific contract events on Taiko such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to Taiko mainnet
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x1670000000000000000000000000000000010001",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x1670000000000000000000000000000000010001",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x1670000000000000000000000000000000010001',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x1670000000000000000000000000000000010001',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Taiko:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x1670000000000000000000000000000000010001',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/taiko/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/taiko/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/taiko/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/taiko/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/taiko/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Taiko RPC Method

# eth_newPendingTransactionFilter - Taiko RPC Method

Creates a filter on Taiko that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for Taiko developers:

- **Mempool Monitoring** - Observe unconfirmed transactions on Taiko to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for Taiko mainnet

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Taiko...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Taiko:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/taiko/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/taiko/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/taiko/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/taiko/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Taiko RPC Method

# eth_protocolVersion - Taiko RPC Method

Returns the current Ethereum protocol version used by the Taiko node.

## When to Use This Method

`eth_protocolVersion` is useful for Taiko developers:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Taiko protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Taiko protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Taiko protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Taiko protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Taiko protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Taiko nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- `web3_clientVersion` - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/taiko/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/taiko/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Taiko RPC Method

# eth_sendRawTransaction - Taiko RPC Method

Submits a pre-signed transaction for broadcast to Taiko.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for Taiko developers:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Taiko
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x1670000000000000000000000000000000010001', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Taiko mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/taiko/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x1670000000000000000000000000000000010001")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/taiko/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/taiko/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/taiko/eth_getTransactionReceipt) - Get transaction result

---

## eth_syncing - Taiko RPC Method

# eth_syncing - Taiko RPC Method

Returns the sync status of your Taiko node - either `false` when fully synced, or an object describing the sync progress.

## When to Use This Method

`eth_syncing` is essential for Taiko developers:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Taiko node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Taiko node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Taiko node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/taiko/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/taiko/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/taiko/net_listening) - Verify node is accepting connections
- `web3_clientVersion` - Get node client info

---

## eth_uninstallFilter - Taiko RPC Method

# eth_uninstallFilter - Taiko RPC Method

Removes a filter on Taiko that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

## When to Use This Method

`eth_uninstallFilter` is important for Taiko developers:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/taiko/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/taiko/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/taiko/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/taiko/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/taiko/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Taiko RPC Method

# net_listening - Taiko RPC Method

Checks whether the connected Taiko client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

## When to Use This Method

`net_listening` is useful for Taiko developers:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Taiko node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Taiko node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Taiko node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/taiko/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/taiko/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/taiko/eth_syncing) - Check node sync progress
- `web3_clientVersion` - Get node client info

---

## net_peerCount - Taiko RPC Method

# net_peerCount - Taiko RPC Method

Returns the number of peers currently connected to your Taiko node.

## When to Use This Method

`net_peerCount` is important for Taiko developers:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Taiko deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Taiko peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Taiko peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Taiko peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Taiko nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/taiko/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/taiko/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/taiko/eth_syncing) - Check node sync progress
- `web3_clientVersion` - Get node client info

---

## net_version - Taiko RPC Method

# net_version - Taiko RPC Method

Returns the current network ID on Taiko as a decimal string. The network ID identifies which network the node is connected to.

## When to Use This Method

`net_version` is essential for Taiko developers:

- **Endpoint Identification** - Confirm your application is connected to the expected Taiko network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Taiko network ID:', networkId);

// Using fetch
const response = await fetch('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Taiko network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Taiko network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/taiko/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/taiko/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/taiko/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/taiko/eth_syncing) - Check node sync progress

---

## rpc_modules - Taiko RPC Method

# rpc_modules - Taiko RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Taiko endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

## When to Use This Method

`rpc_modules` is useful for Taiko developers:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- `web3_clientVersion` - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/taiko/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/taiko/trace_transaction) - Trace namespace example

---

## trace_block - Taiko RPC Method

# trace_block - Taiko RPC Method

Returns traces for all transactions in a block on Taiko.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Taiko
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for Taiko mainnet
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Taiko chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/taiko/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/taiko/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/taiko/trace_get) - Get a specific trace by index

---

## trace_call - Taiko RPC Method

# trace_call - Taiko RPC Method

Traces a call without creating a transaction on Taiko, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Taiko
- **Pre-execution analysis** - Test contract interactions without spending gas for Taiko mainnet
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x1670000000000000000000000000000000010001",
      "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x1670000000000000000000000000000000010001", "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x1670000000000000000000000000000000010001',
    data: '0x70a082310000000000000000000000001670000000000000000000000000000000010001'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x1670000000000000000000000000000000010001',
        'data': '0x70a082310000000000000000000000001670000000000000000000000000000000010001'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/taiko/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/taiko/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/taiko/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Taiko RPC Method

# trace_callMany - Taiko RPC Method

Traces multiple calls in sequence on Taiko, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Taiko
- **Historical state comparison** - Compare how the same call would execute at different points in Taiko chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for Taiko mainnet
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x1670000000000000000000000000000000010001", "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"}, ["trace"]],
      [{"to": "0x1670000000000000000000000000000000010001", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x1670000000000000000000000000000000010001", "data": "0x70a082310000000000000000000000001670000000000000000000000000000000010001"}, ["trace"]],
        [{"to": "0x1670000000000000000000000000000000010001", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x1670000000000000000000000000000000010001', data: '0x70a082310000000000000000000000001670000000000000000000000000000000010001' }, ['trace']],
    [{ to: '0x1670000000000000000000000000000000010001', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x1670000000000000000000000000000000010001', 'data': '0x70a082310000000000000000000000001670000000000000000000000000000000010001'}, ['trace']],
        [{'to': '0x1670000000000000000000000000000000010001', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/taiko/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/taiko/eth_call) - Execute call without trace

---

## trace_filter - Taiko RPC Method

# trace_filter - Taiko RPC Method

Returns traces matching a filter on Taiko.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Taiko
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for Taiko mainnet
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x1670000000000000000000000000000000010001"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x1670000000000000000000000000000000010001"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x1670000000000000000000000000000000010001'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x1670000000000000000000000000000000010001'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/taiko/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/taiko/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/taiko/eth_getLogs) - Filter event logs

---

## trace_get - Taiko RPC Method

# trace_get - Taiko RPC Method

Returns a trace at a specific position within a transaction on Taiko.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Taiko
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for Taiko mainnet
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/taiko/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/taiko/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Taiko RPC Method

# trace_replayBlockTransactions - Taiko RPC Method

Replays all transactions in a block on Taiko and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Taiko
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for Taiko mainnet
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Taiko chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/taiko/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/taiko/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/taiko/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Taiko RPC Method

# trace_replayTransaction - Taiko RPC Method

Replays a transaction on Taiko and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Taiko
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for Taiko mainnet
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/taiko/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/taiko/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/taiko/trace_block) - Get all traces in a block

---

## trace_transaction - Taiko RPC Method

# trace_transaction - Taiko RPC Method

Returns all traces for a specific transaction on Taiko.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for Taiko mainnet
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Taiko
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-taiko-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0xc9aac5d30a3a9eb839f10db814a2cbe8971212bd8c77f8227d30532873be7bbe'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/taiko/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/taiko/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/taiko/trace_filter) - Filter traces by criteria

---

## Tempo RPC with Dwellir

# Tempo RPC with Dwellir

## Tempo RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Tempo supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Tempo?

Tempo is a payments-first EVM blockchain designed for stablecoin settlement and financial application UX. Instead of forcing users to manage a native gas token, Tempo denominates fees in supported USD stablecoins while keeping standard Ethereum JSON-RPC compatibility.

### **Stablecoin-Native Fees**

- **No native gas token** - users pay fees in supported USD stablecoins
- **Predictable pricing** - easier wallet and checkout UX for payment flows
- **Cleaner treasury logic** - applications can reason about settlement costs in dollar terms

### **Built for Payment Workloads**

- **Deterministic settlement** - optimized for fast, reliable payment confirmation
- **Merchant-friendly design** - suitable for payouts, invoices, and treasury automation
- **Wallet-aware fee flows** - fee token preferences can be managed at the account level

### **Standard EVM Tooling**

- **EVM compatible** - keep your Solidity contracts and familiar SDKs
- **Trace and debug ready** - Dwellir exposes `trace_*`, `debug_*`, and `txpool_*`
- **HTTPS and WebSocket** - use the same endpoint shape as other EVM integrations

## Quick Start with Tempo

Connect to Tempo mainnet with Dwellir:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider(
  'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const chainId = await provider.send('eth_chainId', []);
console.log('Tempo chain ID:', parseInt(chainId, 16));

const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);
```

```javascript
const Web3 = require('web3');

const web3 = new Web3(
  'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const chainId = await web3.eth.getChainId();
console.log('Connected to Tempo:', chainId === 4217);

const gasPrice = await web3.eth.getGasPrice();
console.log('Current fee quote:', web3.utils.fromWei(gasPrice, 'gwei'), 'gwei-USD');
```

```typescript
import { createPublicClient, defineChain, http } from 'viem';

const tempo = defineChain({
  id: 4217,
  name: 'Tempo',
  nativeCurrency: {
    name: 'USD',
    symbol: 'USD',
    decimals: 18,
  },
  rpcUrls: {
    default: {
      http: ['https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Tempo Explorer',
      url: 'https://explore.tempo.xyz',
    },
  },
});

const client = createPublicClient({
  chain: tempo,
  transport: http('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

const blockNumber = await client.getBlockNumber();
console.log('Latest block:', blockNumber);
```

```python
from web3 import Web3

web3 = Web3(Web3.HTTPProvider(
  'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'
))

print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # 4217
print('Latest block:', web3.eth.block_number)
```

## Network Information

| Parameter    | Value                     | Details                |
| ------------ | ------------------------- | ---------------------- |
| Chain ID     | 4217                      | Tempo mainnet          |
| Block Time   | \~1 second                | Fast settlement target |
| Fee Model    | Supported USD stablecoins | No native gas token    |
| RPC Standard | Ethereum                  | JSON-RPC 2.0           |

## Tempo Fee Model Notes

Tempo does not behave like a typical ETH-gas chain:

- **No native token balance requirement** for paying fees
- **Fee quotes are stablecoin-denominated**, so wallet and app UX should not assume ETH-style gas handling
- **Fee token preferences matter** because users can pay with supported stablecoins instead of a single mandatory gas asset

If your wallet or payment flow assumes `eth_getBalance` reflects spendable fee balance, adjust that logic for Tempo before launch.

## API Reference

Tempo supports standard Ethereum JSON-RPC methods, and Dwellir's endpoint also exposes trace, debug, and txpool namespaces for production operations and debugging.

## Common Integration Patterns

### Stablecoin Payment Monitoring

```javascript
async function waitForSettlement(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);
  console.log('Settled in block:', receipt.blockNumber);
  return receipt;
}
```

### Fee Estimation in Stablecoin Terms

```javascript
const feeData = await provider.getFeeData();
const gasEstimate = await provider.estimateGas(tx);

const approxUsdCost =
  Number(feeData.gasPrice) / 1e9 * Number(gasEstimate) / 1e9;

console.log('Estimated fee (USD):', approxUsdCost);
```

### Trace Support for Payment Debugging

```javascript
const trace = await provider.send('debug_traceTransaction', [
  '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28'
]);

console.log('Trace result:', trace);
```

## Related guides

- [Stablecoin L1 RPC guide: Arc, Tempo, Plasma and Stable](https://www.dwellir.com/blog/stablechain-rpc-guide)
- [Top Tempo RPC providers compared](https://www.dwellir.com/blog/top-tempo-rpc-providers)

---

## debug_traceBlock - Tempo RPC Method

# debug_traceBlock - Tempo RPC Method

Traces all transactions in a block on Tempo by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Tempo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Tempo
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Tempo:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Tempo blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/tempo/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/tempo/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/tempo/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/tempo/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Tempo RPC Method

# debug_traceBlockByHash - Tempo RPC Method

Traces all transactions in a block on Tempo identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Tempo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Tempo
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Tempo:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Tempo:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/tempo/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/tempo/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/tempo/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/tempo/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tempo/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Tempo RPC Method

# debug_traceBlockByNumber - Tempo RPC Method

Traces all transactions in a block on Tempo identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Tempo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Tempo execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Tempo:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Tempo:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/tempo/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/tempo/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/tempo/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/tempo/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Tempo RPC Method

# debug_traceCall - Tempo RPC Method

Traces a call on Tempo without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Tempo - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Tempo
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
        "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
        "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    data: '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    data: '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    'data': '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
        "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Tempo to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Tempo:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Tempo:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/tempo/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/tempo/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/tempo/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/tempo/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Tempo RPC Method

# debug_traceTransaction - Tempo RPC Method

Traces a transaction execution on Tempo by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Tempo
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/tempo/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/tempo/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Tempo RPC Method

# eth_accounts - Tempo RPC Method

Returns a list of addresses owned by the client on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/tempo/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/tempo/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Tempo RPC Method

# eth_blockNumber - Tempo RPC Method

Returns the number of the most recent block on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_blockNumber` is fundamental for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Syncing Applications** - Keep your dApp in sync with the latest Tempo blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Tempo block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Tempo block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Tempo block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Tempo block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Tempo block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Tempo:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Tempo:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Tempo node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tempo/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/tempo/eth_syncing) - Check if node is still syncing

---

## eth_call - Tempo RPC Method

# eth_call - Tempo RPC Method

Executes a new message call immediately without creating a transaction on Tempo. Used for reading smart contract state.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

The `eth_call` method serves these key scenarios for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Tempo
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';
const walletAddress = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Tempo. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Tempo
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Tempo

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    data := common.FromHex("0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Tempo RPC Method

# eth_chainId - Tempo RPC Method

Returns the chain ID used for transaction signing on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_chainId` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/tempo/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/tempo/eth_syncing) - Check sync status

---

## eth_estimateGas - Tempo RPC Method

# eth_estimateGas - Tempo RPC Method

Estimates the gas necessary to execute a transaction on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Tempo
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x0bd34b0a5be345c9bf7a147eb698e993511180cb', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x0bd34b0a5be345c9bf7a147eb698e993511180cb', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Tempo.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Tempo may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x0bd34b0a5be345c9bf7a147eb698e993511180cb', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/tempo/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Tempo RPC Method

# eth_feeHistory - Tempo RPC Method

Returns historical gas fee data on Tempo, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Tempo without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Tempo.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Tempo) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/tempo/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/tempo/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Tempo RPC Method

# eth_gasPrice - Tempo RPC Method

Returns the current gas price on Tempo in wei.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Tempo
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Tempo. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Tempo, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Tempo: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Tempo supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/tempo/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/tempo/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Tempo RPC Method

# eth_getBalance - Tempo RPC Method

Returns the balance of a given address on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getBalance` is fundamental for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Tempo
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Tempo
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Tempo. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Tempo`);
  return balance;
}

displayBalance('0x0bd34b0a5be345c9bf7a147eb698e993511180cb');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Tempo at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Tempo')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Tempo')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Tempo.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/tempo/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/tempo/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Tempo RPC Method

# eth_getBlockByHash - Tempo RPC Method

Returns information about a block by hash on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getBlockByHash` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Tempo
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on a payments-first EVM chain with deterministic settlement and stablecoin-native fees
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Tempo.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on a payments-first EVM chain with deterministic settlement and stablecoin-native fees.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Tempo.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/tempo/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Tempo RPC Method

# eth_getBlockByNumber - Tempo RPC Method

Returns information about a block by block number on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getBlockByNumber` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Tempo
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on a payments-first EVM chain with deterministic settlement and stablecoin-native fees

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Tempo with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Tempo. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on a payments-first EVM chain with deterministic settlement and stablecoin-native fees expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/tempo/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tempo/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tempo/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Tempo RPC Method

# eth_getBlockReceipts - Tempo RPC Method

Returns all transaction receipts for a block on Tempo. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getBlockReceipts` is useful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Tempo, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Tempo. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on a payments-first EVM chain with deterministic settlement and stablecoin-native fees, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tempo/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tempo/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Tempo RPC Method

# eth_getCode - Tempo RPC Method

Returns the bytecode at a given address on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getCode` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Tempo
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Tempo:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Tempo:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/tempo/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/tempo/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Tempo RPC Method

# eth_getFilterChanges - Tempo RPC Method

Polls a filter on Tempo for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getFilterChanges` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Tempo
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Tempo:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/tempo/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/tempo/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/tempo/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/tempo/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/tempo/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Tempo RPC Method

# eth_getFilterLogs - Tempo RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Tempo. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getFilterLogs` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Tempo
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/tempo/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/tempo/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/tempo/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/tempo/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Tempo RPC Method

# eth_getLogs - Tempo RPC Method

Returns an array of all logs matching a given filter object on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Tempo for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Tempo
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Tempo.

```javascript
const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Tempo enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Tempo, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/tempo/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/tempo/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Tempo RPC Method

# eth_getStorageAt - Tempo RPC Method

Returns the value from a storage position at a given address on Tempo. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getStorageAt` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **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 merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **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": [
    "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "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-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x0bd34b0a5be345c9bf7a147eb698e993511180cb', '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-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';

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-tempo-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 = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
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-tempo-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-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    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 Tempo:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-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-tempo-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 = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';
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 Tempo:`);
  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/tempo/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/tempo/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/tempo/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Tempo RPC Method

# eth_getTransactionByHash - Tempo RPC Method

Returns the information about a transaction by transaction hash on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getTransactionByHash` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Tempo
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on a payments-first EVM chain with deterministic settlement and stablecoin-native fees

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Tempo. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Tempo. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on a payments-first EVM chain with deterministic settlement and stablecoin-native fees.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tempo/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Tempo RPC Method

# eth_getTransactionCount - Tempo RPC Method

Returns the number of transactions sent from an address on Tempo, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getTransactionCount` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Tempo
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x0bd34b0a5be345c9bf7a147eb698e993511180cb', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Tempo nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x0bd34b0a5be345c9bf7a147eb698e993511180cb'
nonce = get_transaction_count(address)
print(f'Tempo nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Tempo nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Tempo:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x0bd34b0a5be345c9bf7a147eb698e993511180cb');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/tempo/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tempo/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tempo/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Tempo RPC Method

# eth_getTransactionReceipt - Tempo RPC Method

Returns the receipt of a transaction by transaction hash on Tempo. Receipt is only available for mined transactions.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_getTransactionReceipt` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Tempo and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on a payments-first EVM chain with deterministic settlement and stablecoin-native fees by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Tempo. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Tempo, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on a payments-first EVM chain with deterministic settlement and stablecoin-native fees. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on a payments-first EVM chain with deterministic settlement and stablecoin-native fees
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tempo/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/tempo/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Tempo RPC Method

# eth_hashrate - Tempo RPC Method

Returns the legacy `eth_hashrate` compatibility value on Tempo. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Tempo hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Tempo hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Tempo hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Tempo hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Tempo hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- `eth_mining` - Check if the node is actively mining
- `eth_coinbase` - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/tempo/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Tempo RPC Method

# eth_maxPriorityFeePerGas - Tempo RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Tempo. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Tempo
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Tempo priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Tempo priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Tempo priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Tempo:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Tempo:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/tempo/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/tempo/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tempo/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_newBlockFilter - Tempo RPC Method

# eth_newBlockFilter - Tempo RPC Method

Creates a filter on Tempo that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_newBlockFilter` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Block Monitoring** - Detect new blocks on Tempo as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Tempo:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/tempo/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/tempo/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/tempo/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tempo/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Tempo RPC Method

# eth_newFilter - Tempo RPC Method

Creates a filter object on Tempo based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_newFilter` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Event Monitoring** - Subscribe to specific contract events on Tempo such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Tempo:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/tempo/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/tempo/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/tempo/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/tempo/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/tempo/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Tempo RPC Method

# eth_newPendingTransactionFilter - Tempo RPC Method

Creates a filter on Tempo that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Mempool Monitoring** - Observe unconfirmed transactions on Tempo to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Tempo...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Tempo:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/tempo/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/tempo/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tempo/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Tempo RPC Method

# eth_protocolVersion - Tempo RPC Method

Returns the current Ethereum protocol version used by the Tempo node.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_protocolVersion` is useful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Tempo protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Tempo protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Tempo protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Tempo protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Tempo protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Tempo nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/tempo/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/tempo/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/tempo/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Tempo RPC Method

# eth_sendRawTransaction - Tempo RPC Method

Submits a pre-signed transaction for broadcast to Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Tempo
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x0bd34b0a5be345c9bf7a147eb698e993511180cb', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Tempo mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/tempo/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x0bd34b0a5be345c9bf7a147eb698e993511180cb")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/tempo/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tempo/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Tempo RPC Method

# eth_sendTransaction - Tempo RPC Method

Creates and sends a new transaction from an unlocked account on Tempo. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Tempo tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Tempo tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Tempo tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tempo tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Tempo tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Tempo dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/tempo/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/tempo/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Tempo RPC Method

# eth_signTransaction - Tempo RPC Method

Signs a transaction with the private key of the specified account on Tempo without submitting it to the network.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Tempo tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Tempo tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Tempo tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Tempo:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/tempo/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/tempo/eth_accounts) - List accounts available for signing

---

## eth_syncing - Tempo RPC Method

# eth_syncing - Tempo RPC Method

Returns the sync status of your Tempo node - either `false` when fully synced, or an object describing the sync progress.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_syncing` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Tempo node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Tempo node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Tempo node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/tempo/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/tempo/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/tempo/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/tempo/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Tempo RPC Method

# eth_uninstallFilter - Tempo RPC Method

Removes a filter on Tempo that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`eth_uninstallFilter` is important for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/tempo/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/tempo/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/tempo/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/tempo/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/tempo/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Tempo RPC Method

# net_listening - Tempo RPC Method

Checks whether the connected Tempo client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`net_listening` is useful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Tempo node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Tempo node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Tempo node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/tempo/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/tempo/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/tempo/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/tempo/web3_clientVersion) - Get node client info

---

## net_peerCount - Tempo RPC Method

# net_peerCount - Tempo RPC Method

Returns the number of peers currently connected to your Tempo node.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`net_peerCount` is important for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Tempo deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Tempo peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Tempo peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Tempo peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Tempo nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/tempo/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/tempo/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/tempo/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/tempo/web3_clientVersion) - Get node client info

---

## net_version - Tempo RPC Method

# net_version - Tempo RPC Method

Returns the current network ID on Tempo as a decimal string. The network ID identifies which network the node is connected to.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`net_version` is essential for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Endpoint Identification** - Confirm your application is connected to the expected Tempo network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Tempo network ID:', networkId);

// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Tempo network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Tempo network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/tempo/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/tempo/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/tempo/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/tempo/eth_syncing) - Check node sync progress

---

## rpc_modules - Tempo RPC Method

# rpc_modules - Tempo RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Tempo endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`rpc_modules` is useful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/tempo/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/tempo/debug_traceTransaction) - Debug namespace example
- [`trace_transaction`](https://www.dwellir.com/docs/tempo/trace_transaction) - Trace namespace example

---

## trace_block - Tempo RPC Method

# trace_block - Tempo RPC Method

Returns traces for all transactions in a block on Tempo.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace all transactions in a block by block number** - Get the full trace of every transaction in a block on Tempo
- **Block-level execution analysis** - Inspect all internal calls, transfers, and contract interactions within a block for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **MEV research** - Analyze transaction ordering, sandwich patterns, and arbitrage across a full block
- **Historical block replay** - Replay and trace blocks at any point in Tempo chain history

## Best Practices

- Similar to trace\_replayBlockTransactions but without explicit replay configuration
- Use block hash variant (`debug_traceBlockByHash`) for reorg-safe queries
- Traces from dense blocks can be very large; process results in batches
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag (latest, earliest, pending)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_block",
  "params": ["latest"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_block",
    "params": ["latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_block', ['latest']);
console.log('Traces in block:', traces.length);
for (const trace of traces.slice(0, 5)) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_block', ['latest'])
for trace in traces['result'][:5]:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/tempo/trace_filter) - Filter traces by address or block range
- [`trace_transaction`](https://www.dwellir.com/docs/tempo/trace_transaction) - Trace a specific transaction
- [`trace_get`](https://www.dwellir.com/docs/tempo/trace_get) - Get a specific trace by index

---

## trace_call - Tempo RPC Method

# trace_call - Tempo RPC Method

Traces a call without creating a transaction on Tempo, returning the trace output.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace simulated execution of multiple calls** - Preview internal calls before committing a transaction on Tempo
- **Pre-execution analysis** - Test contract interactions without spending gas for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Batch trace simulations** - Execute several calls sequentially where each can depend on prior state changes
- **Contract interaction analysis** - Understand how multiple contracts interact through a simulated execution chain

## Best Practices

- Similar to debug\_traceCall but supports multiple calls in one request
- Each call has its own trace configuration for fine-grained control
- Use for batch simulation analysis of dependent call sequences
- Requires archive node access for historical block tracing

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (from, to, gas, value, data)
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_call",
  "params": [
    {
      "to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"
    },
    ["trace"],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_call",
    "params": [
      {"to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb", "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"},
      ["trace"],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_call', [
  {
    to: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
    data: '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb'
  },
  ['trace'],
  'latest'
]);
console.log('Trace output:', result.trace);
console.log('VM trace:', result.vmTrace);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_call', [
    {
        'to': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb',
        'data': '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb'
    },
    ['trace'],
    'latest'
])
print(f'Trace: {result["result"]["trace"]}')
```

## Related Methods

- [`trace_filter`](https://www.dwellir.com/docs/tempo/trace_filter) - Filter traces by criteria
- [`eth_call`](https://www.dwellir.com/docs/tempo/eth_call) - Execute call without trace
- [`trace_transaction`](https://www.dwellir.com/docs/tempo/trace_transaction) - Trace a specific transaction

---

## trace_callMany - Tempo RPC Method

# trace_callMany - Tempo RPC Method

Traces multiple calls in sequence on Tempo, where each call can depend on the state changes of the previous one.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Trace multiple calls across different blocks** - Execute calls at different historical block heights for cross-block state analysis on Tempo
- **Historical state comparison** - Compare how the same call would execute at different points in Tempo chain history
- **Multi-step simulation** - Simulate a sequence of dependent calls where each step builds on the previous one for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Batch operation tracing** - Preview multiple contract interactions in a single RPC request

## Best Practices

- Each call specifies its own block number for cross-block analysis
- Useful for comparing state across time without multiple requests
- More efficient than separate trace\_call requests for multi-step workflows
- Requires archive node access for historical block state

## Request Parameters

- `calls` (`Array, required`): Array of [callObject, traceTypes] pairs
- `blockNumber` (`QUANTITY|TAG, optional`): Block number or tag (default: latest)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_callMany",
  "params": [
    [
      [{"to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb", "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"}, ["trace"]],
      [{"to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb", "data": "0x18160ddd"}, ["trace"]]
    ],
    "latest"
  ],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_callMany",
    "params": [
      [
        [{"to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb", "data": "0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb"}, ["trace"]],
        [{"to": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb", "data": "0x18160ddd"}, ["trace"]]
      ],
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_callMany', [
  [
    [{ to: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb', data: '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb' }, ['trace']],
    [{ to: '0x0bd34b0a5be345c9bf7a147eb698e993511180cb', data: '0x18160ddd' }, ['trace']]
  ],
  'latest'
]);
console.log('Call results:', results.length);
for (const result of results) {
  console.log('  Output:', result.output);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_callMany', [
    [
        [{'to': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb', 'data': '0x70a082310000000000000000000000000bd34b0a5be345c9bf7a147eb698e993511180cb'}, ['trace']],
        [{'to': '0x0bd34b0a5be345c9bf7a147eb698e993511180cb', 'data': '0x18160ddd'}, ['trace']]
    ],
    'latest'
])
for i, result in enumerate(results['result']):
    print(f'Call {i}: output={result.get("output", "N/A")}')
```

## Related Methods

- [`trace_call`](https://www.dwellir.com/docs/tempo/trace_call) - Trace a single call
- [`eth_call`](https://www.dwellir.com/docs/tempo/eth_call) - Execute call without trace

---

## trace_filter - Tempo RPC Method

# trace_filter - Tempo RPC Method

Returns traces matching a filter on Tempo.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Search for traces matching address criteria** - Find all internal transactions involving a specific address on Tempo
- **Find all interactions with a contract** - Track every call, delegate call, and create operation targeting a contract for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Audit contract usage patterns** - Analyze how contracts are used over time across block ranges
- **Forensic analysis** - Investigate transaction patterns and address-level activity across the chain

## Best Practices

- Very resource-intensive on large block ranges; narrow the range as much as possible
- Use specific fromAddress or toAddress filters to reduce response size
- Limit block range to small chunks and paginate results
- Many provider-managed endpoints disable this method due to computational cost

## Request Parameters

- `filterObject` (`Object, required`): Filter criteria (see below)
- `fromBlock` (`QUANTITY|TAG, required`): Start block (hex or tag)
- `toBlock` (`QUANTITY|TAG, required`): End block (hex or tag)
- `fromAddress` (`Array<DATA>, required`): Filter by sender addresses
- `toAddress` (`Array<DATA>, required`): Filter by receiver addresses
- `after` (`QUANTITY, required`): Offset for pagination
- `count` (`QUANTITY, required`): Max results to return

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_filter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "toAddress": ["0x0bd34b0a5be345c9bf7a147eb698e993511180cb"],
    "count": 10
  }],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_filter",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "toAddress": ["0x0bd34b0a5be345c9bf7a147eb698e993511180cb"],
      "count": 10
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_filter', [{
  fromBlock: 'latest',
  toBlock: 'latest',
  toAddress: ['0x0bd34b0a5be345c9bf7a147eb698e993511180cb'],
  count: 10
}]);
console.log('Matching traces:', traces.length);
for (const trace of traces) {
  console.log(`  Block ${trace.blockNumber}: ${trace.action.from} -> ${trace.action.to}`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_filter', [{
    'fromBlock': 'latest',
    'toBlock': 'latest',
    'toAddress': ['0x0bd34b0a5be345c9bf7a147eb698e993511180cb'],
    'count': 10
}])
for trace in traces['result']:
    action = trace['action']
    print(f'Block {trace["blockNumber"]}: {action["from"]} -> {action.get("to", "CREATE")}')
```

## Related Methods

- [`trace_block`](https://www.dwellir.com/docs/tempo/trace_block) - Get all traces in a block
- [`trace_transaction`](https://www.dwellir.com/docs/tempo/trace_transaction) - Get traces for a specific transaction
- [`eth_getLogs`](https://www.dwellir.com/docs/tempo/eth_getLogs) - Filter event logs

---

## trace_get - Tempo RPC Method

# trace_get - Tempo RPC Method

Returns a trace at a specific position within a transaction on Tempo.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get a specific trace by transaction hash and trace index** - Retrieve individual trace entries from a transaction on Tempo
- **Pinpoint specific internal calls** - Isolate a particular sub-call at a known position in the call tree for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Targeted debugging** - Investigate a specific call depth without retrieving the full transaction trace
- **Combine with trace\_transaction** - Discover trace indices from the full trace, then fetch details individually

## Best Practices

- Requires knowing the trace address and index in advance
- Combine with trace\_transaction to discover trace indices first
- Supports fetching multiple traces by passing an array of indices
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `indices` (`Array<QUANTITY>, required`): Trace index positions (e.g., ["0x0"] for the first trace)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_get",
  "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28", ["0x0"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_get",
    "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28", ["0x0"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const trace = await provider.send('trace_get', [
  '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28',
  ['0x0']
]);
console.log('Trace type:', trace.type);
console.log('From:', trace.action.from);
console.log('To:', trace.action.to);
console.log('Value:', trace.action.value);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('trace_get', [
    '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28',
    ['0x0']
])
result = trace['result']
print(f'Type: {result["type"]}')
print(f'From: {result["action"]["from"]}')
print(f'To: {result["action"]["to"]}')
```

## Related Methods

- [`trace_transaction`](https://www.dwellir.com/docs/tempo/trace_transaction) - Get all traces for a transaction
- [`trace_block`](https://www.dwellir.com/docs/tempo/trace_block) - Get all traces in a block

---

## trace_replayBlockTransactions - Tempo RPC Method

# trace_replayBlockTransactions - Tempo RPC Method

Replays all transactions in a block on Tempo and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay all transactions in a block** - Get vmTrace, stateDiff, and trace for every transaction in a block on Tempo
- **Comprehensive block-level execution analysis** - Audit exactly how each transaction in a block modified state for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Audit entire block execution** - Verify that all transactions in a block executed as expected
- **Historical block replay** - Re-execute blocks at any point in Tempo chain history

## Best Practices

- Very resource-intensive; each transaction is fully traced with all requested types
- Limit to small blocks or use specific tracer types to reduce response size
- Request only the trace types you actually need to minimize overhead
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex or tag
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayBlockTransactions",
  "params": ["latest", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayBlockTransactions",
    "params": ["latest", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const results = await provider.send('trace_replayBlockTransactions', [
  'latest',
  ['trace']
]);
console.log('Transactions replayed:', results.length);
for (const result of results.slice(0, 3)) {
  console.log(`  Tx ${result.transactionHash}: ${result.trace.length} traces`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

results = w3.provider.make_request('trace_replayBlockTransactions', [
    'latest',
    ['trace']
])
for tx in results['result'][:3]:
    print(f'Tx {tx["transactionHash"]}: {len(tx["trace"])} traces')
```

## Related Methods

- [`trace_replayTransaction`](https://www.dwellir.com/docs/tempo/trace_replayTransaction) - Replay a single transaction
- [`trace_block`](https://www.dwellir.com/docs/tempo/trace_block) - Get traces without replay
- [`trace_filter`](https://www.dwellir.com/docs/tempo/trace_filter) - Filter traces by criteria

---

## trace_replayTransaction - Tempo RPC Method

# trace_replayTransaction - Tempo RPC Method

Replays a transaction on Tempo and returns the requested traces.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Replay and trace a transaction execution** - Get vmTrace, stateDiff, and trace in a single call for comprehensive analysis on Tempo
- **State diff extraction** - See exact account balance, nonce, code, and storage changes caused by a transaction for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **VM trace debugging** - Get opcode-level execution details alongside the structured call trace
- **Comprehensive transaction analysis** - Combine all three trace types in one request for complete execution visibility

## Best Practices

- Returns more detailed trace data than debug\_traceTransaction
- Combine vmTrace with trace array for a full picture of opcode and call-level execution
- Request all three trace types (trace, vmTrace, stateDiff) for maximum detail
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `traceTypes` (`Array, required`): Trace types: ["trace"], ["vmTrace"], ["stateDiff"], or combinations

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_replayTransaction",
  "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28", ["trace"]],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_replayTransaction",
    "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28", ["trace"]],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const result = await provider.send('trace_replayTransaction', [
  '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28',
  ['trace']
]);
console.log('Trace:', result.trace.length, 'entries');
console.log('State diff:', result.stateDiff ? 'present' : 'not requested');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

result = w3.provider.make_request('trace_replayTransaction', [
    '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28',
    ['trace']
])
trace = result['result']
print(f'Trace entries: {len(trace["trace"])}')
```

## Related Methods

- [`trace_replayBlockTransactions`](https://www.dwellir.com/docs/tempo/trace_replayBlockTransactions) - Replay all transactions in a block
- [`trace_transaction`](https://www.dwellir.com/docs/tempo/trace_transaction) - Get traces without replay
- [`trace_block`](https://www.dwellir.com/docs/tempo/trace_block) - Get all traces in a block

---

## trace_transaction - Tempo RPC Method

# trace_transaction - Tempo RPC Method

Returns all traces for a specific transaction on Tempo.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Get parity-style transaction trace** - Retrieve the full trace of all internal calls, state changes, and value transfers for merchant settlement, treasury operations, payout automation, and stablecoin-native financial applications
- **Analyze internal calls and state changes** - See every sub-call, delegate call, and contract creation triggered by a transaction on Tempo
- **Audit transaction execution paths** - Follow the exact flow of execution through contracts to verify correctness
- **Track value flows** - Trace how funds move through multiple contracts in a single transaction

## Best Practices

- Parity-style traces are more detailed than the debug namespace equivalent
- Use trace\_replayTransaction for combined trace, vmTrace, and stateDiff output
- Results include both stateDiff and vmTrace sections for comprehensive analysis
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "trace_transaction",
  "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28"],
  "id": 1
}
```

## Response Fields

This method returns no documented fields.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const traces = await provider.send('trace_transaction', [
  '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28'
]);
console.log('Traces:', traces.length);
for (const trace of traces) {
  console.log(`  ${trace.action.from} -> ${trace.action.to} (${trace.type})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('trace_transaction', [
    '0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28'
])
for trace in traces['result']:
    action = trace['action']
    print(f'{action["from"]} -> {action.get("to", "CREATE")} ({trace["type"]})')
```

## Related Methods

- [`trace_get`](https://www.dwellir.com/docs/tempo/trace_get) - Get a specific trace by index
- [`trace_block`](https://www.dwellir.com/docs/tempo/trace_block) - Get all traces in a block
- [`trace_filter`](https://www.dwellir.com/docs/tempo/trace_filter) - Filter traces by criteria

---

## txpool_content - Tempo RPC Method

# txpool_content - Tempo RPC Method

Returns the full pending and queued transaction pool for the connected Tempo endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`txpool_content` is useful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/tempo/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tempo/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tempo/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Tempo RPC Method

# txpool_status - Tempo RPC Method

Returns transaction pool counters for the connected Tempo endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`txpool_status` is valuable for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/tempo/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/tempo/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/tempo/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Tempo RPC Method

# web3_clientVersion - Tempo RPC Method

Returns the current client software version string for your Tempo node, including the client name, version number, OS, and runtime.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

## When to Use This Method

`web3_clientVersion` is valuable for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Tempo client:', clientVersion);

// Using fetch
const response = await fetch('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Tempo client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Tempo client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/tempo/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/tempo/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/tempo/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/tempo/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Tempo RPC Method

# web3_sha3 - Tempo RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Tempo.

> **Why Tempo?** Build on a payments-first EVM chain with deterministic settlement and stablecoin-native fees with no native gas token, fees denominated in supported USD stablecoins, and full EVM RPC compatibility.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for payment application developers, wallet teams, stablecoin issuers, and treasury automation builders:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-tempo-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/tempo/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/tempo/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/tempo/web3_clientVersion) - Get node client version

---

## TRON (TRX) - High-Performance Blockchain Documentation

# TRON (TRX) - High-Performance Blockchain Documentation

## TRON RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where TRON supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on TRON?

TRON is a high-performance blockchain platform designed for mass adoption with 2000+ TPS, free daily transactions, and a thriving ecosystem of DeFi, gaming, and entertainment dApps.

### **Unmatched Performance**

- **2000+ TPS** - Process thousands of transactions per second
- **3-second blocks** - Near-instant transaction finality
- **Free transactions** - Daily free bandwidth and energy for users
- **$0.000005 average fee** - Ultra-low costs for paid transactions

### **Massive Adoption**

- **200M+ accounts** - One of the largest blockchain user bases
- **8B+ transactions** - Proven scalability in production
- **$15B+ TVL** - Thriving DeFi ecosystem
- **USDT dominance** - 50%+ of all USDT circulates on TRON

### **Developer Friendly**

- **Solidity support** - Deploy Ethereum smart contracts with minimal changes
- **TVM compatibility** - TRON Virtual Machine based on EVM
- **Energy & Bandwidth** - Unique resource model for gas optimization
- **Multi-signature** - Native support for complex wallet operations

## Quick Start with TRON

Connect to TRON's high-performance network with Dwellir's optimized endpoints:

- **Wallet & HTTP APIs** (e.g. `/wallet/getnowblock`) use `https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/<method>`.
- **JSON-RPC methods** (all `eth_*`, `net_*`, `web3_*`) should target `https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc`.
  All JSON-RPC requests must be sent as POST calls with a JSON body. Replace `YOUR_API_KEY` with your key before using the examples.

### Installation & Setup

TronWeb
JavaScript (Fetch)
Python

```javascript
const TronWeb = require('tronweb');

// Initialize TronWeb with Dwellir endpoint
const tronWeb = new TronWeb({
  fullHost: 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY',
  headers: { "TRON-PRO-API-KEY": 'YOUR_API_KEY' },
  privateKey: 'your-private-key'
});

// Get account information
const account = await tronWeb.trx.getAccount('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN');
console.log('Balance:', tronWeb.fromSun(account.balance), 'TRX');

// Send TRX transaction
const tx = await tronWeb.trx.sendTransaction(
  'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
  1000000, // Amount in SUN (1 TRX = 1,000,000 SUN)
  'your-private-key'
);
console.log('Transaction:', tx.txid);
```

```javascript
// Direct HTTP API calls
const TRON_HTTP_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';
const TRON_JSON_RPC = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc';

// Get account balance
async function getBalance(address) {
  const response = await fetch(`${TRON_HTTP_API}/wallet/getaccount`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      address: address,
      visible: true
    })
  });

  const data = await response.json();
  return data.balance / 1000000; // Convert SUN to TRX
}

// Get latest block
async function getLatestBlock() {
  const response = await fetch(`${TRON_HTTP_API}/wallet/getnowblock`);
  return response.json();
}

// Call a JSON-RPC method
async function getBlockNumber() {
  const response = await fetch(TRON_JSON_RPC, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_blockNumber',
      params: [],
      id: 1,
    }),
  });

  const data = await response.json();
  return parseInt(data.result, 16);
}
```

```python
from tronpy import Tron
from tronpy.keys import PrivateKey

# Connect to TRON mainnet via Dwellir
client = Tron(network='mainnet')
client.provider.endpoint_uri = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY'

# Get account information
account = client.get_account('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN')
print(f"Balance: {account.balance / 1_000_000} TRX")

# Send TRX transaction
priv_key = PrivateKey(bytes.fromhex("your_private_key_hex"))
txn = (
    client.trx.transfer("from_address", "to_address", 1_000_000)
    .memo("Transaction memo")
    .build()
    .sign(priv_key)
)
result = txn.broadcast()
print(f"Transaction ID: {result['txid']}")
```

## Network Information

### Mainnet Configuration

| Parameter      | Value                                     | Details |
| -------------- | ----------------------------------------- | ------- |
| Network Name   | TRON Mainnet                              |         |
| Chain ID       | `728126428` (0x2B6653DC)                  |         |
| Currency       | TRX                                       |         |
| Decimal        | 6 (1 TRX = 1,000,000 SUN)                 |         |
| Block Explorer | [TronScan Explorer](https://tronscan.org) |         |
| Official Site  | [TRON Website](https://tron.network)      |         |

### Address Format

TRON uses Base58 encoded addresses starting with 'T':

| Parameter | Value                                | Details         |
| --------- | ------------------------------------ | --------------- |
| Example   | `TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN` |                 |
| Length    | 34 characters                        |                 |
| Checksum  | Built-in                             | Error detection |

## Core RPC Methods

### Account & Wallet Methods

#### wallet/getaccount

Get account information including balance, resources, and tokens:

```javascript
const account = await fetch(`${TRON_API}/wallet/getaccount`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    address: 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
    visible: true
  })
});
```

#### wallet/getaccountresource

Get bandwidth and energy resources:

```javascript
const resources = await fetch(`${TRON_API}/wallet/getaccountresource`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    address: 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
    visible: true
  })
});
```

### Transaction Methods

#### wallet/createtransaction

Create a TRX transfer transaction:

```javascript
const transaction = await fetch(`${TRON_API}/wallet/createtransaction`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    to_address: 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
    owner_address: 'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
    amount: 1000000, // 1 TRX in SUN
    visible: true
  })
});
```

#### wallet/broadcasttransaction

Broadcast a signed transaction:

```javascript
const broadcast = await fetch(`${TRON_API}/wallet/broadcasttransaction`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(signedTransaction)
});
```

### Block Methods

#### wallet/getnowblock

Get the latest block:

```javascript
const latestBlock = await fetch(`${TRON_API}/wallet/getnowblock`);
const block = await latestBlock.json();
console.log('Block number:', block.block_header.raw_data.number);
```

#### wallet/getblock

Get block by hash or number:

```javascript
const block = await fetch(`${TRON_API}/wallet/getblock`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    id_or_num: "0000000002FAB1B8", // Block hash or number
    detail: true
  })
});
```

### Smart Contract Methods

#### wallet/triggersmartcontract

Call a smart contract function:

```javascript
const contractCall = await fetch(`${TRON_API}/wallet/triggersmartcontract`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    contract_address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT contract
    function_selector: 'balanceOf(address)',
    parameter: '0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863',
    owner_address: 'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
    visible: true
  })
});
```

## TRC20 Token Operations

### Working with USDT and Other TRC20 Tokens

```javascript
// TRC20 USDT Contract
const USDT_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';

// Get USDT balance
async function getUSDTBalance(address) {
  const { constant_result } = await tronWeb.transactionBuilder.triggerConstantContract(
    USDT_CONTRACT,
    'balanceOf(address)',
    {},
    [{type: 'address', value: address}]
  );

  return tronWeb.toDecimal('0x' + constant_result[0]) / 1e6;
}

// Transfer USDT
async function transferUSDT(to, amount) {
  const contract = await tronWeb.contract().at(USDT_CONTRACT);
  const tx = await contract.transfer(to, amount * 1e6).send();
  return tx;
}
```

### Popular TRC20 Tokens

| Token | Contract Address                   | Decimals |
| ----- | ---------------------------------- | -------- |
| USDT  | TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t | 6        |
| USDC  | TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8 | 6        |
| TUSD  | TUpMhErZL2fhh4sVNULAbNKLokS4GjC1F4 | 18       |
| WTRX  | TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR | 6        |
| JST   | TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9 | 18       |

## Energy & Bandwidth System

### Understanding TRON Resources

TRON uses a unique resource model instead of gas fees:

1. **Bandwidth Points** - For normal transactions
2. **Energy** - For smart contract execution
3. **TRX Fee** - Fallback when resources are exhausted

```javascript
// Freeze TRX for energy
async function freezeForEnergy(amount) {
  const tx = await tronWeb.transactionBuilder.freezeBalance(
    amount * 1e6, // Amount in SUN
    3, // Duration in days
    'ENERGY',
    ownerAddress
  );
  const signed = await tronWeb.trx.sign(tx);
  return await tronWeb.trx.broadcast(signed);
}

// Get account resources
async function getResources(address) {
  const resources = await tronWeb.trx.getAccountResources(address);
  return {
    bandwidth: resources.freeNetLimit + (resources.NetLimit || 0),
    energy: resources.EnergyLimit || 0,
    freeTransactions: resources.freeNetUsed < resources.freeNetLimit
  };
}
```

### Resource Optimization Tips

1. **Free Transactions** - Every account gets 5000 free bandwidth daily
2. **Stake TRX** - Freeze TRX to get energy for smart contracts
3. **Energy Rental** - Rent energy from platforms like JustLend
4. **Multi-signature** - Combine resources from multiple accounts

## DeFi Integration

### Connecting to TRON DeFi Protocols

```javascript
// JustSwap V2 Router
const JUSTSWAP_ROUTER = 'TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax';

// Swap TRX for USDT
async function swapTRXforUSDT(amountTRX) {
  const contract = await tronWeb.contract().at(JUSTSWAP_ROUTER);

  const path = [
    'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR', // WTRX
    'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'  // USDT
  ];

  const tx = await contract.swapExactETHForTokens(
    0, // Min amount out
    path,
    userAddress,
    Date.now() + 60000 // Deadline
  ).send({
    callValue: amountTRX * 1e6
  });

  return tx;
}
```

### Popular TRON DeFi Protocols

| Protocol | Category | TVL    | Contract                           |
| -------- | -------- | ------ | ---------------------------------- |
| JustLend | Lending  | $5B+   | Multiple contracts                 |
| SUN.io   | DEX      | $2B+   | TKkeiboTkxXKJpbmVFbv4a8ov5rAfRDMf9 |
| JustSwap | AMM DEX  | $500M+ | TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax |

## Transaction Signing

### Signing Transactions with Private Key

```javascript
// Sign transaction locally
async function signTransaction(transaction, privateKey) {
  const tronWeb = new TronWeb({
    fullHost: 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY',
    privateKey: privateKey
  });

  const signedTx = await tronWeb.trx.sign(transaction);
  return signedTx;
}

// Multi-signature transaction
async function multiSigTransaction(transaction, privateKeys) {
  let signedTx = transaction;

  for (const key of privateKeys) {
    const tronWeb = new TronWeb({
      fullHost: 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY',
      privateKey: key
    });
    signedTx = await tronWeb.trx.multiSign(signedTx);
  }

  return signedTx;
}
```

## Best Practices

### Error Handling

```javascript
class TronAPIError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
  }
}

async function safeAPICall(url, options) {
  try {
    const response = await fetch(url, options);
    const data = await response.json();

    if (data.Error) {
      throw new TronAPIError(data.Error, data.code);
    }

    return data;
  } catch (error) {
    if (error.code === 'BANDWIDTH_ERROR') {
      console.error('Insufficient bandwidth. Consider freezing TRX.');
    } else if (error.code === 'CONTRACT_VALIDATE_ERROR') {
      console.error('Smart contract validation failed.');
    }
    throw error;
  }
}
```

### Rate Limiting

```javascript
class RateLimiter {
  constructor(maxRequests = 10, interval = 1000) {
    this.maxRequests = maxRequests;
    this.interval = interval;
    this.requests = [];
  }

  async throttle() {
    const now = Date.now();
    this.requests = this.requests.filter(time => now - time < this.interval);

    if (this.requests.length >= this.maxRequests) {
      const waitTime = this.interval - (now - this.requests[0]);
      await new Promise(resolve => setTimeout(resolve, waitTime));
      return this.throttle();
    }

    this.requests.push(now);
  }
}

const limiter = new RateLimiter(100, 1000); // 100 requests per second

async function apiCall(endpoint, options) {
  await limiter.throttle();
  return fetch(endpoint, options);
}
```

## Performance Optimization

### Batch Operations

```javascript
// Batch transfer to multiple addresses
async function batchTransfer(transfers) {
  const transactions = [];

  for (const { to, amount } of transfers) {
    const tx = await tronWeb.transactionBuilder.sendTrx(
      to,
      amount * 1e6,
      fromAddress
    );
    transactions.push(tx);
  }

  // Sign all transactions
  const signedTxs = await Promise.all(
    transactions.map(tx => tronWeb.trx.sign(tx))
  );

  // Broadcast all transactions
  const results = await Promise.all(
    signedTxs.map(tx => tronWeb.trx.broadcast(tx))
  );

  return results;
}
```

### Caching Strategies

```javascript
class TronCache {
  constructor(ttl = 60000) { // 1 minute default TTL
    this.cache = new Map();
    this.ttl = ttl;
  }

  set(key, value) {
    this.cache.set(key, {
      value,
      expiry: Date.now() + this.ttl
    });
  }

  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;

    if (Date.now() > item.expiry) {
      this.cache.delete(key);
      return null;
    }

    return item.value;
  }
}

const cache = new TronCache();

async function getCachedBalance(address) {
  const cached = cache.get(`balance:${address}`);
  if (cached) return cached;

  const balance = await getBalance(address);
  cache.set(`balance:${address}`, balance);
  return balance;
}
```

## Security Best Practices

### Private Key Management

```javascript
// Never expose private keys in code
const privateKey = process.env.TRON_PRIVATE_KEY;

// Use hardware wallets for production
import TronStation from 'tronstation';

async function signWithHardware(transaction) {
  const tronStation = new TronStation();
  const signed = await tronStation.signTransaction(transaction);
  return signed;
}

// Validate addresses
function isValidTronAddress(address) {
  try {
    return TronWeb.isAddress(address);
  } catch {
    return false;
  }
}
```

## Common Use Cases

### NFT Minting (TRC721)

```javascript
async function mintNFT(contractAddress, recipient, tokenURI) {
  const contract = await tronWeb.contract().at(contractAddress);

  const tx = await contract.mint(
    recipient,
    tokenURI
  ).send({
    feeLimit: 100_000_000, // 100 TRX max fee
    shouldPollResponse: true
  });

  return tx;
}
```

### Stablecoin Payments

```javascript
async function acceptUSDTPayment(amount, memo) {
  // Generate unique payment address
  const paymentAddress = await generatePaymentAddress();

  // Monitor for incoming USDT
  const interval = setInterval(async () => {
    const balance = await getUSDTBalance(paymentAddress);

    if (balance >= amount) {
      clearInterval(interval);
      await processPayment(paymentAddress, amount, memo);
    }
  }, 3000); // Check every 3 seconds

  return paymentAddress;
}
```

### DAO Voting

```javascript
async function castVote(proposalId, support, reason) {
  const daoContract = await tronWeb.contract().at(DAO_CONTRACT);

  const tx = await daoContract.castVoteWithReason(
    proposalId,
    support,
    reason
  ).send({
    feeLimit: 50_000_000
  });

  return tx;
}
```

## Migration from Ethereum

### Key Differences

| Feature               | Ethereum     | TRON                     |
| --------------------- | ------------ | ------------------------ |
| Address Format        | 0x... (hex)  | T... (base58)            |
| Gas Model             | ETH for gas  | Bandwidth + Energy       |
| Block Time            | \~12 seconds | 3 seconds                |
| Free Transactions     | No           | Yes (5000 bandwidth/day) |
| Native Token Decimals | 18           | 6                        |

### Contract Migration

```solidity
// Ethereum contract
contract EthereumToken {
    mapping(address => uint256) balances;

    function transfer(address to, uint256 amount) public {
        require(balances[msg.sender] >= amount);
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }
}

// TRON contract (minimal changes)
contract TronToken {
    mapping(address => uint256) balances;

    function transfer(address to, uint256 amount) public {
        require(balances[msg.sender] >= amount);
        balances[msg.sender] = balances[msg.sender].sub(amount);
        balances[to] = balances[to].add(amount);
    }
}
```

## Support & Resources

### Official Resources

- **Documentation**: [TRON developer docs](https://developers.tron.network)
- **GitHub**: [TRON protocol GitHub](https://github.com/tronprotocol)
- **Discord**: [TRON Discord](https://discord.gg/tron)
- **Twitter**: [@trondao](https://twitter.com/trondao)
- **TronScan**: [TronScan](https://tronscan.org)

### Development Tools

- **TronWeb**: Official JavaScript library
- **TronBox**: Development framework
- **TronGrid**: API service
- **TronStation**: Wallet SDK

### Dwellir Support

- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)
- **Status Page**: [status.dwellir.com](https://status.dwellir.com)
- **Support**: <support@dwellir.com>
- **Documentation**: [Dwellir documentation](https://www.dwellir.com/docs)

### Related Reading

- [Best Tron RPC Providers 2026](https://www.dwellir.com/blog/best-tron-rpc-providers)

## Start Building on TRON

Ready to leverage TRON's high performance and massive user base? Get started with Dwellir's optimized infrastructure:

Launch Your TRON dApp Today
Access TRON's 2000+ TPS network with enterprise-grade RPC endpoints

Get Your Free API Key

***

*Need help? Check our [API reference](https://www.dwellir.com/docs/tron/wallet-getaccount) or [contact support](mailto:support@dwellir.com).*

---

## eth_accounts - TRON RPC Method

# eth_accounts - TRON RPC Method

Returns a list of addresses owned by the client on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for TRON developers building payment rails, exchanges, and consumer crypto applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/tron/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/tron/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - TRON RPC Method

# eth_blockNumber - TRON RPC Method

Returns the number of the most recent block on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_blockNumber` is fundamental for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Syncing Applications** - Keep your dApp in sync with the latest TRON blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('TRON block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const blockNumber = await provider.getBlockNumber();
console.log('TRON block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'TRON block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))
print(f'TRON block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("TRON block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on TRON:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on TRON:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your TRON node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tron/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tron/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/tron/eth_syncing) - Check if node is still syncing

---

## eth_call - TRON RPC Method

# eth_call - TRON RPC Method

Executes a new message call immediately without creating a transaction on TRON. Used for reading smart contract state.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

The `eth_call` method serves these key scenarios for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on TRON
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const tokenAddress = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';
const walletAddress = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on TRON. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const routerAddress = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on TRON
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on TRON

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "data": "0x70a08231000000000000000000000000c7885b2334355ba766f54a3ad14d5a5339934bb3"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "data": "0x70a08231000000000000000000000000c7885b2334355ba766f54a3ad14d5a5339934bb3"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xc7885b2334355ba766f54a3ad14d5a5339934bb3',
    '0xc7885b2334355ba766f54a3ad14d5a5339934bb3'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    data := common.FromHex("0x70a08231000000000000000000000000c7885b2334355ba766f54a3ad14d5a5339934bb3")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/tron/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tron/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - TRON RPC Method

# eth_chainId - TRON RPC Method

Returns the chain ID used for transaction signing on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_chainId` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/tron/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/tron/eth_syncing) - Check sync status

---

## eth_estimateGas - TRON RPC Method

# eth_estimateGas - TRON RPC Method

Estimates the gas necessary to execute a transaction on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on TRON
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xc7885b2334355ba766f54a3ad14d5a5339934bb3', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xc7885b2334355ba766f54a3ad14d5a5339934bb3', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on TRON.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like TRON may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xc7885b2334355ba766f54a3ad14d5a5339934bb3',
  '0xc7885b2334355ba766f54a3ad14d5a5339934bb3',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "to": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "to": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xc7885b2334355ba766f54a3ad14d5a5339934bb3', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/tron/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tron/eth_sendRawTransaction) - Send transaction

---

## eth_gasPrice - TRON RPC Method

# eth_gasPrice - TRON RPC Method

Returns the current gas price on TRON in wei.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on TRON
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of TRON. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on TRON, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on TRON: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if TRON supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current TRON gas price in hex. Dwellir's shared mainnet endpoint currently returns 0x64 (100 sun).

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x64"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_gasPrice does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- `eth_maxPriorityFeePerGas` - Get priority fee (EIP-1559)
- `eth_feeHistory` - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/tron/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - TRON RPC Method

# eth_getBalance - TRON RPC Method

Returns the balance of a given address on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getBalance` is fundamental for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on TRON
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to TRON
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on TRON. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} TRON`);
  return balance;
}

displayBalance('0xc7885b2334355ba766f54a3ad14d5a5339934bb3');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on TRON at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))
address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 TRON')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 TRON')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on TRON.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")

    address := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/tron/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/tron/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - TRON RPC Method

# eth_getBlockByHash - TRON RPC Method

Returns information about a block by hash on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getBlockByHash` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on TRON
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on TRON.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on TRON.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")

    knownHash := common.HexToHash("0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Sample Freshness

Use a recent block hash when you copy these examples into your own tooling. Shared RPC infrastructure can return `null` if the block is no longer available on the node you are querying, so replace placeholders with a fresh block hash when you test or automate against this method later.

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const blockHash = '0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

block_hash = '0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tron/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/tron/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - TRON RPC Method

# eth_getBlockByNumber - TRON RPC Method

Returns information about a block by block number on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getBlockByNumber` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on TRON
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on TRON with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on TRON. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/tron/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tron/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tron/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - TRON RPC Method

# eth_getBlockReceipts - TRON RPC Method

Returns all transaction receipts for a block on TRON. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getBlockReceipts` is useful for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for TRON, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on TRON. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x0000000004d4dd2a62243e06966cb322aefec631e1ec0ce68ed3f2482cecccb9",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tron/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/tron/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tron/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - TRON RPC Method

# eth_getCode - TRON RPC Method

Returns the bytecode at a given address on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getCode` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on TRON
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on TRON:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on TRON:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/tron/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/tron/eth_getStorageAt) - Get contract storage

---

## eth_getLogs - TRON RPC Method

# eth_getLogs - TRON RPC Method

Returns an array of all logs matching a given filter object on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on TRON for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on TRON
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const tokenAddress = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on TRON.

```javascript
const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if TRON enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on TRON, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xc7885b2334355ba766f54a3ad14d5a5339934bb3',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xc7885b2334355ba766f54a3ad14d5a5339934bb3',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- `eth_newFilter` - Create a filter for logs
- `eth_getFilterChanges` - Poll filter for new logs

---

## eth_getStorageAt - TRON RPC Method

# eth_getStorageAt - TRON RPC Method

Returns the value from a storage position at a given address on TRON. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getStorageAt` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **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 TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **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": [
    "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xc7885b2334355ba766f54a3ad14d5a5339934bb3', '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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';

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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getStorageAt',
            'params': [address, hex(position), block],
            'id': 1
        }
    )
    return response.json()['result']

address = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3'
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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))
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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    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 TRON:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

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-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

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 = '0xc7885b2334355ba766f54a3ad14d5a5339934bb3';
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 TRON:`);
  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/tron/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/tron/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/tron/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/tron/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - TRON RPC Method

# eth_getTransactionByHash - TRON RPC Method

Returns the information about a transaction by transaction hash on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getTransactionByHash` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on TRON
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on TRON. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on TRON. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")

    txHash := common.HexToHash("0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Sample Freshness

Use a recent transaction hash when you test this method in your own environment. If the transaction is no longer available on the node you are querying, TRON can return `null`, so replace placeholders with a fresh transaction hash whenever you re-run the examples.

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const txHash = '0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

tx_hash = '0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tron/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tron/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - TRON RPC Method

# eth_getTransactionCount - TRON RPC Method

Returns the number of transactions sent from an address on TRON, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getTransactionCount` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on TRON
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Current Shared Endpoint Behavior

Dwellir's shared TRON JSON-RPC endpoint currently returns `-32601` for `eth_getTransactionCount`. Keep this page as a compatibility reference for TRON clients that expose the EVM nonce surface, but feature-detect the method before you depend on it in production code.

If you are building against the shared public endpoint, plan around the native TRON wallet APIs for transaction construction instead of assuming Ethereum-style nonce reads are available everywhere.

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal nonce on TRON nodes that expose the EVM-compatible transaction count method.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_getTransactionCount does not exist/is not available",
    "data": "{}"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
async function readTronNonce(provider, address) {
  try {
    return await provider.send('eth_getTransactionCount', [address, 'latest']);
  } catch (error) {
    if (String(error.message).includes('does not exist')) {
      return null;
    }
    throw error;
  }
}

const nonce = await readTronNonce(provider, '0xc7885b2334355ba766f54a3ad14d5a5339934bb3');

if (nonce === null) {
  console.log('eth_getTransactionCount is not currently available on this TRON endpoint');
} else {
  console.log('TRON nonce:', Number(nonce));
}
```

```python
import requests

response = requests.post(
    'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_getTransactionCount',
        'params': ['0xc7885b2334355ba766f54a3ad14d5a5339934bb3', 'latest'],
        'id': 1,
    },
)

payload = response.json()

if 'error' in payload:
    print(payload['error']['message'])
else:
    print(int(payload['result'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(
        context.Background(),
        &result,
        "eth_getTransactionCount",
        "0xc7885b2334355ba766f54a3ad14d5a5339934bb3",
        "latest",
    )

    if err != nil {
        fmt.Printf("eth_getTransactionCount unavailable: %v\n", err)
        return
    }

    fmt.Printf("TRON nonce: %s\n", result)
}
```

## Common Use Cases

### 1. Feature-detect nonce support during startup

```javascript
async function supportsTronNonceReads(provider, address) {
  try {
    await provider.send('eth_getTransactionCount', [address, 'latest']);
    return true;
  } catch (error) {
    return !String(error.message).includes('does not exist');
  }
}
```

### 2. Fallback to the native TRON wallet flow

```javascript
async function prepareTronSubmission({ provider, address }) {
  const hasNonceSurface = await supportsTronNonceReads(provider, address);

  if (!hasNonceSurface) {
    return {
      mode: 'tron-wallet-api',
      note: 'Use wallet/createtransaction or wallet/triggersmartcontract on this endpoint.',
    };
  }

  return {
    mode: 'evm-compatible',
    nonce: await provider.send('eth_getTransactionCount', [address, 'latest']),
  };
}
```

### 3. Keep compatibility logic explicit

```python
def classify_tron_nonce_support(payload: dict) -> str:
    if payload.get('error', {}).get('code') == -32601:
        return 'shared-endpoint-without-eth_getTransactionCount'

    return 'endpoint-exposes-evm-nonce-surface'
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/tron/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/tron/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tron/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tron/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - TRON RPC Method

# eth_getTransactionReceipt - TRON RPC Method

Returns the receipt of a transaction by transaction hash on TRON. Receipt is only available for mined transactions.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_getTransactionReceipt` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on TRON and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for TRC-20 transfers, wallet operations, and EVM-compatible smart contract integrations
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on TRON. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on TRON, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")

    txHash := common.HexToHash("0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const txHash = '0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

tx_hash = '0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xdcfaa73d566d819ff95b8a9ae944e34c011fb16dd55bce7830a80016c54acf71")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/tron/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/tron/eth_getLogs) - Query logs by filter

---

## eth_sendRawTransaction - TRON RPC Method

# eth_sendRawTransaction - TRON RPC Method

Submits a pre-signed transaction for broadcast to TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to TRON
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xc7885b2334355ba766f54a3ad14d5a5339934bb3', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the TRON mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/tron/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xc7885b2334355ba766f54a3ad14d5a5339934bb3")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/tron/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/tron/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/tron/eth_getTransactionReceipt) - Get transaction result

---

## eth_syncing - TRON RPC Method

# eth_syncing - TRON RPC Method

Returns the sync status of your TRON node - either `false` when fully synced, or an object describing the sync progress.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`eth_syncing` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('TRON node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('TRON node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("TRON node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/tron/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/tron/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/tron/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/tron/web3_clientVersion) - Get node client info

---

## net_listening - TRON RPC Method

# net_listening - TRON RPC Method

Checks whether the connected TRON client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`net_listening` is useful for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

try {
  const listening = await provider.send('net_listening', []);
  console.log('TRON node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

try:
    listening = w3.net.listening
    print(f'TRON node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("TRON node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/tron/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/tron/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/tron/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/tron/web3_clientVersion) - Get node client info

---

## net_peerCount - TRON RPC Method

# net_peerCount - TRON RPC Method

Returns the number of peers currently connected to your TRON node.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`net_peerCount` is important for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific TRON deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`TRON peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

peer_count = w3.net.peer_count
print(f'TRON peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("TRON peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of TRON nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/tron/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/tron/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/tron/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/tron/web3_clientVersion) - Get node client info

---

## net_version - TRON RPC Method

# net_version - TRON RPC Method

Returns the current network ID on TRON as a decimal string. The network ID identifies which network the node is connected to.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`net_version` is essential for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Endpoint Identification** - Confirm your application is connected to the expected TRON network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Current Network ID

TRON mainnet currently returns `0x2b6653dc` from both `net_version` and `eth_chainId` on Dwellir's shared JSON-RPC endpoint. Treat that value as the canonical identity check when you are validating routing, signing, or environment selection in production code.

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Hex-encoded TRON network identifier. Dwellir's shared mainnet endpoint currently returns 0x2b6653dc.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2b6653dc"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1,
  }),
});

const { result } = await response.json();
console.log('TRON network ID:', result); // "0x2b6653dc"
console.log('Is TRON mainnet:', result === '0x2b6653dc');
```

```python
import requests

response = requests.post(
    'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1,
    },
)

network_id = response.json()['result']
print(f'TRON network ID: {network_id}')
print(f'Is TRON mainnet: {network_id == "0x2b6653dc"}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var networkID string
    err = client.CallContext(context.Background(), &networkID, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("TRON network ID: %s\n", networkID)
    fmt.Printf("Is TRON mainnet: %t\n", networkID == "0x2b6653dc")
}
```

## Common Use Cases

### 1. Gate startup on the expected TRON network ID

```javascript
async function assertTronMainnet(provider) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== '0x2b6653dc') {
    throw new Error(`Unexpected TRON network ID: ${networkId}`);
  }

  return networkId;
}
```

### 2. Cross-check `net_version` and `eth_chainId`

```javascript
async function readTronIdentity(provider) {
  const [networkId, chainId] = await Promise.all([
    provider.send('net_version', []),
    provider.send('eth_chainId', []),
  ]);

  console.log({ networkId, chainId });

  if (networkId !== chainId) {
    throw new Error(`TRON identity mismatch: ${networkId} vs ${chainId}`);
  }

  return { networkId, chainId };
}
```

### 3. Route environment-specific config

```python
TRON_NETWORKS = {
    '0x2b6653dc': 'tron-mainnet',
}

def resolve_tron_environment(network_id: str) -> str:
    if network_id not in TRON_NETWORKS:
        raise ValueError(f'Unsupported TRON network id: {network_id}')

    return TRON_NETWORKS[network_id]
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/tron/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/tron/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/tron/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/tron/eth_syncing) - Check node sync progress

---

## TRC20 Token Transfers - Complete Guide

# TRC20 Token Transfers - Complete Guide

**Dwellir's TRON endpoints** provide comprehensive TRC20 token support with optimized smart contract interactions.
Build powerful token applications with our complete TRC20 integration guide.

[Start building with TRC20 tokens](https://dashboard.dwellir.com/register)

Complete guide to implementing TRC20 token transfers on the TRON network. Learn how to check balances, approve spending, transfer tokens, and handle all TRC20 operations.

## Overview of TRC20 Standard

TRC20 is TRON's fungible token standard, similar to Ethereum's ERC20. Popular tokens include:

- **USDT** (Tether) - `TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t`
- **USDC** (USD Coin) - `TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8`
- **JST** (JUST) - `TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9`
- **WTRX** (Wrapped TRX) - `TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR`

### Key TRC20 Functions

- `balanceOf(address)` - Check token balance
- `transfer(address,uint256)` - Transfer tokens
- `approve(address,uint256)` - Approve spending
- `transferFrom(address,address,uint256)` - Transfer on behalf
- `allowance(address,address)` - Check approved amount

## Implementation Examples

cURL
JavaScript
Python

```bash
#!/bin/bash
API_KEY="YOUR_API_KEY"
BASE_URL="https://api-tron-mainnet.n.dwellir.com/$API_KEY"

# Popular TRC20 token addresses
USDT_ADDRESS="TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
USDC_ADDRESS="TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8"
JST_ADDRESS="TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9"
WTRX_ADDRESS="TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR"

# Function to encode address for contract parameters
encode_address() {
  local address=$1
  # Simplified encoding - use proper tools in production
  echo "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863"
}

# Function to encode uint256
encode_uint256() {
  local value=$1
  printf "%064x" "$value"
}

# Get TRC20 token balance
get_token_balance() {
  local token_address=$1
  local wallet_address=$2
  
  local encoded_address=$(encode_address "$wallet_address")
  
  curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"balanceOf(address)\",
      \"parameter\": \"$encoded_address\",
      \"owner_address\": \"$wallet_address\",
      \"visible\": true
    }" | jq -r '.constant_result[0] // "0"' | xargs printf "%d"
}

# Get token info (symbol, decimals, name)
get_token_info() {
  local token_address=$1
  
  echo "Getting token information for $token_address..."
  
  # Get symbol
  local symbol_result=$(curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"symbol()\",
      \"owner_address\": \"$token_address\",
      \"visible\": true
    }")
  
  # Get decimals
  local decimals_result=$(curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"decimals()\",
      \"owner_address\": \"$token_address\",
      \"visible\": true
    }")
  
  # Get name
  local name_result=$(curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"name()\",
      \"owner_address\": \"$token_address\",
      \"visible\": true
    }")
  
  local symbol=$(echo "$symbol_result" | jq -r '.constant_result[0] // "UNKNOWN"')
  local decimals_hex=$(echo "$decimals_result" | jq -r '.constant_result[0] // "6"')
  local decimals=$(printf "%d" "0x$decimals_hex" 2>/dev/null || echo "6")
  local name=$(echo "$name_result" | jq -r '.constant_result[0] // "Unknown"')
  
  echo "Symbol: $symbol"
  echo "Decimals: $decimals"
  echo "Name: $name"
  
  # Export for use in other functions
  export TOKEN_SYMBOL="$symbol"
  export TOKEN_DECIMALS="$decimals"
  export TOKEN_NAME="$name"
}

# Create TRC20 transfer transaction
create_token_transfer() {
  local token_address=$1
  local from_address=$2
  local to_address=$3
  local amount=$4  # Amount in token's smallest unit
  
  local encoded_to=$(encode_address "$to_address")
  local encoded_amount=$(encode_uint256 "$amount")
  local parameters="${encoded_to}${encoded_amount}"
  
  curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"transfer(address,uint256)\",
      \"parameter\": \"$parameters\",
      \"owner_address\": \"$from_address\",
      \"visible\": true
    }"
}

# Create TRC20 approval transaction
create_token_approval() {
  local token_address=$1
  local owner_address=$2
  local spender_address=$3
  local amount=$4
  
  local encoded_spender=$(encode_address "$spender_address")
  local encoded_amount=$(encode_uint256 "$amount")
  local parameters="${encoded_spender}${encoded_amount}"
  
  curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"approve(address,uint256)\",
      \"parameter\": \"$parameters\",
      \"owner_address\": \"$owner_address\",
      \"visible\": true
    }"
}

# Get allowance
get_allowance() {
  local token_address=$1
  local owner_address=$2
  local spender_address=$3
  
  local encoded_owner=$(encode_address "$owner_address")
  local encoded_spender=$(encode_address "$spender_address")
  local parameters="${encoded_owner}${encoded_spender}"
  
  curl -s -X POST "$BASE_URL/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$token_address\",
      \"function_selector\": \"allowance(address,address)\",
      \"parameter\": \"$parameters\",
      \"owner_address\": \"$owner_address\",
      \"visible\": true
    }" | jq -r '.constant_result[0] // "0"' | xargs printf "%d"
}

# Get formatted balance
get_formatted_balance() {
  local token_address=$1
  local wallet_address=$2
  
  echo "Getting balance for $wallet_address..."
  
  # Get token info first
  get_token_info "$token_address"
  
  # Get balance
  local balance=$(get_token_balance "$token_address" "$wallet_address")
  
  # Calculate formatted balance
  local formatted_balance
  if [ "$TOKEN_DECIMALS" -gt 0 ]; then
    formatted_balance=$(echo "scale=6; $balance / (10^$TOKEN_DECIMALS)" | bc -l)
  else
    formatted_balance="$balance"
  fi
  
  echo "Raw balance: $balance"
  echo "Formatted balance: $formatted_balance $TOKEN_SYMBOL"
}

# Portfolio balance checker
check_portfolio() {
  local wallet_address=$1
  
  echo "=== Portfolio Balances for $wallet_address ==="
  echo ""
  
  # USDT
  echo "USDT Balance:"
  get_formatted_balance "$USDT_ADDRESS" "$wallet_address"
  echo ""
  
  # USDC
  echo "USDC Balance:"
  get_formatted_balance "$USDC_ADDRESS" "$wallet_address"
  echo ""
  
  # JST
  echo "JST Balance:"
  get_formatted_balance "$JST_ADDRESS" "$wallet_address"
  echo ""
  
  # WTRX
  echo "WTRX Balance:"
  get_formatted_balance "$WTRX_ADDRESS" "$wallet_address"
  echo ""
}

# Complete transfer workflow
transfer_usdt() {
  local from_address=$1
  local to_address=$2
  local amount_usdt=$3
  
  echo "=== USDT Transfer Workflow ==="
  echo "From: $from_address"
  echo "To: $to_address"
  echo "Amount: $amount_usdt USDT"
  echo ""
  
  # 1. Get token info
  echo "1. Getting USDT token info..."
  get_token_info "$USDT_ADDRESS"
  echo ""
  
  # 2. Check balance
  echo "2. Checking balance..."
  local balance=$(get_token_balance "$USDT_ADDRESS" "$from_address")
  local formatted_balance=$(echo "scale=6; $balance / (10^$TOKEN_DECIMALS)" | bc -l)
  echo "Current balance: $formatted_balance USDT"
  
  # Check if sufficient balance
  if (( $(echo "$formatted_balance < $amount_usdt" | bc -l) )); then
    echo "❌ Insufficient balance!"
    echo "Have: $formatted_balance USDT"
    echo "Need: $amount_usdt USDT"
    return 1
  fi
  
  # 3. Calculate amount in smallest unit
  local amount_in_decimals=$(echo "scale=0; $amount_usdt * (10^$TOKEN_DECIMALS) / 1" | bc -l)
  echo "Amount in smallest unit: $amount_in_decimals"
  echo ""
  
  # 4. Create transfer transaction
  echo "3. Creating transfer transaction..."
  local transfer_result=$(create_token_transfer "$USDT_ADDRESS" "$from_address" "$to_address" "$amount_in_decimals")
  
  # Check if successful
  local success=$(echo "$transfer_result" | jq -r '.result.result // false')
  
  if [ "$success" = "true" ]; then
    local tx_id=$(echo "$transfer_result" | jq -r '.transaction.txID')
    local energy_used=$(echo "$transfer_result" | jq -r '.energy_used // 0')
    
    echo "✅ Transfer transaction created successfully!"
    echo "Transaction ID: $tx_id"
    echo "Energy required: $energy_used"
    echo ""
    echo "Next steps:"
    echo "1. Sign the transaction with your private key"
    echo "2. Broadcast the signed transaction"
    echo "3. Monitor for confirmation"
  else
    local error_message=$(echo "$transfer_result" | jq -r '.result.message // "Unknown error"')
    echo "❌ Transfer creation failed: $error_message"
    return 1
  fi
}

# Approval workflow
setup_approval() {
  local token_address=$1
  local owner_address=$2
  local spender_address=$3
  local amount=$4
  
  echo "=== Token Approval Workflow ==="
  echo "Token: $token_address"
  echo "Owner: $owner_address"
  echo "Spender: $spender_address"
  echo "Amount: $amount"
  echo ""
  
  # 1. Check current allowance
  echo "1. Checking current allowance..."
  local current_allowance=$(get_allowance "$token_address" "$owner_address" "$spender_address")
  echo "Current allowance: $current_allowance"
  
  # 2. Create approval if needed
  if [ "$current_allowance" -lt "$amount" ]; then
    echo ""
    echo "2. Creating approval transaction..."
    local approval_result=$(create_token_approval "$token_address" "$owner_address" "$spender_address" "$amount")
    
    local success=$(echo "$approval_result" | jq -r '.result.result // false')
    
    if [ "$success" = "true" ]; then
      local tx_id=$(echo "$approval_result" | jq -r '.transaction.txID')
      echo "✅ Approval transaction created: $tx_id"
    else
      local error_message=$(echo "$approval_result" | jq -r '.result.message // "Unknown error"')
      echo "❌ Approval creation failed: $error_message"
      return 1
    fi
  else
    echo "✅ Sufficient allowance already exists"
  fi
}

# Main script usage
case "${1:-help}" in
  "balance")
    if [ -z "$2" ] || [ -z "$3" ]; then
      echo "Usage: $0 balance TOKEN_ADDRESS WALLET_ADDRESS"
      exit 1
    fi
    get_formatted_balance "$2" "$3"
    ;;
  "portfolio")
    if [ -z "$2" ]; then
      echo "Usage: $0 portfolio WALLET_ADDRESS"
      exit 1
    fi
    check_portfolio "$2"
    ;;
  "transfer")
    if [ -z "$4" ]; then
      echo "Usage: $0 transfer FROM_ADDRESS TO_ADDRESS AMOUNT"
      exit 1
    fi
    transfer_usdt "$2" "$3" "$4"
    ;;
  "approve")
    if [ -z "$5" ]; then
      echo "Usage: $0 approve TOKEN_ADDRESS OWNER_ADDRESS SPENDER_ADDRESS AMOUNT"
      exit 1
    fi
    setup_approval "$2" "$3" "$4" "$5"
    ;;
  "info")
    if [ -z "$2" ]; then
      echo "Usage: $0 info TOKEN_ADDRESS"
      exit 1
    fi
    get_token_info "$2"
    ;;
  *)
    echo "TRON TRC20 Token Manager"
    echo ""
    echo "Usage: $0 {balance|portfolio|transfer|approve|info} [args...]"
    echo ""
    echo "Commands:"
    echo "  balance TOKEN_ADDRESS WALLET_ADDRESS           - Get token balance"
    echo "  portfolio WALLET_ADDRESS                       - Get portfolio balances"
    echo "  transfer FROM_ADDRESS TO_ADDRESS AMOUNT        - Transfer USDT"
    echo "  approve TOKEN_ADDRESS OWNER SPENDER AMOUNT     - Setup token approval"
    echo "  info TOKEN_ADDRESS                             - Get token information"
    echo ""
    echo "Examples:"
    echo "  $0 balance $USDT_ADDRESS TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
    echo "  $0 portfolio TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
    echo "  $0 transfer TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN 10"
    echo "  $0 info $USDT_ADDRESS"
    ;;
esac
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// TRC20 Token Manager
class TRC20TokenManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
    
    // Popular TRC20 contracts
    this.tokens = {
      USDT: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
      USDC: 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8',
      JST: 'TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9',
      WTRX: 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR'
    };
  }
  
  // Get token balance
  async getBalance(tokenAddress, walletAddress) {
    try {
      const encodedAddress = this.encodeAddress(walletAddress);
      
      const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          contract_address: tokenAddress,
          function_selector: 'balanceOf(address)',
          parameter: encodedAddress,
          owner_address: walletAddress,
          visible: true
        })
      });
      
      const result = await response.json();
      
      if (result.result?.result && result.constant_result?.[0]) {
        const balanceHex = result.constant_result[0];
        return BigInt('0x' + balanceHex).toString();
      }
      
      return '0';
    } catch (error) {
      console.error('Error getting balance:', error);
      throw error;
    }
  }
  
  // Get token info (decimals, symbol, name)
  async getTokenInfo(tokenAddress) {
    try {
      const [decimals, symbol, name, totalSupply] = await Promise.all([
        this.callViewFunction(tokenAddress, 'decimals()'),
        this.callViewFunction(tokenAddress, 'symbol()'),
        this.callViewFunction(tokenAddress, 'name()'),
        this.callViewFunction(tokenAddress, 'totalSupply()')
      ]);
      
      return {
        decimals: parseInt(decimals || '6'),
        symbol: this.parseString(symbol) || 'UNKNOWN',
        name: this.parseString(name) || 'Unknown Token',
        totalSupply: totalSupply || '0',
        address: tokenAddress
      };
    } catch (error) {
      console.error('Error getting token info:', error);
      throw error;
    }
  }
  
  // Create transfer transaction
  async createTransfer(tokenAddress, fromAddress, toAddress, amount) {
    try {
      const encodedTo = this.encodeAddress(toAddress);
      const encodedAmount = this.encodeUint256(amount);
      const parameters = encodedTo + encodedAmount;
      
      const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          contract_address: tokenAddress,
          function_selector: 'transfer(address,uint256)',
          parameter: parameters,
          owner_address: fromAddress,
          visible: true
        })
      });
      
      const result = await response.json();
      
      if (result.result?.result) {
        return {
          success: true,
          transaction: result.transaction,
          energyUsed: result.energy_used || 0,
          txId: result.transaction?.txID
        };
      } else {
        throw new Error(result.result?.message || 'Transfer creation failed');
      }
    } catch (error) {
      console.error('Error creating transfer:', error);
      throw error;
    }
  }
  
  // Create approval transaction
  async createApproval(tokenAddress, ownerAddress, spenderAddress, amount) {
    try {
      const encodedSpender = this.encodeAddress(spenderAddress);
      const encodedAmount = this.encodeUint256(amount);
      const parameters = encodedSpender + encodedAmount;
      
      const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          contract_address: tokenAddress,
          function_selector: 'approve(address,uint256)',
          parameter: parameters,
          owner_address: ownerAddress,
          visible: true
        })
      });
      
      const result = await response.json();
      
      if (result.result?.result) {
        return {
          success: true,
          transaction: result.transaction,
          energyUsed: result.energy_used || 0,
          txId: result.transaction?.txID
        };
      } else {
        throw new Error(result.result?.message || 'Approval creation failed');
      }
    } catch (error) {
      console.error('Error creating approval:', error);
      throw error;
    }
  }
  
  // Get allowance
  async getAllowance(tokenAddress, ownerAddress, spenderAddress) {
    try {
      const encodedOwner = this.encodeAddress(ownerAddress);
      const encodedSpender = this.encodeAddress(spenderAddress);
      const parameters = encodedOwner + encodedSpender;
      
      const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          contract_address: tokenAddress,
          function_selector: 'allowance(address,address)',
          parameter: parameters,
          owner_address: ownerAddress,
          visible: true
        })
      });
      
      const result = await response.json();
      
      if (result.result?.result && result.constant_result?.[0]) {
        const allowanceHex = result.constant_result[0];
        return BigInt('0x' + allowanceHex).toString();
      }
      
      return '0';
    } catch (error) {
      console.error('Error getting allowance:', error);
      throw error;
    }
  }
  
  // Create transferFrom transaction (spend allowance)
  async createTransferFrom(tokenAddress, spenderAddress, fromAddress, toAddress, amount) {
    try {
      const encodedFrom = this.encodeAddress(fromAddress);
      const encodedTo = this.encodeAddress(toAddress);
      const encodedAmount = this.encodeUint256(amount);
      const parameters = encodedFrom + encodedTo + encodedAmount;
      
      const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          contract_address: tokenAddress,
          function_selector: 'transferFrom(address,address,uint256)',
          parameter: parameters,
          owner_address: spenderAddress,
          visible: true
        })
      });
      
      const result = await response.json();
      
      if (result.result?.result) {
        return {
          success: true,
          transaction: result.transaction,
          energyUsed: result.energy_used || 0,
          txId: result.transaction?.txID
        };
      } else {
        throw new Error(result.result?.message || 'TransferFrom creation failed');
      }
    } catch (error) {
      console.error('Error creating transferFrom:', error);
      throw error;
    }
  }
  
  // Get formatted balance with token info
  async getFormattedBalance(tokenAddress, walletAddress) {
    try {
      const [balance, tokenInfo] = await Promise.all([
        this.getBalance(tokenAddress, walletAddress),
        this.getTokenInfo(tokenAddress)
      ]);
      
      const formattedBalance = parseFloat(balance) / Math.pow(10, tokenInfo.decimals);
      
      return {
        raw: balance,
        formatted: formattedBalance,
        decimals: tokenInfo.decimals,
        symbol: tokenInfo.symbol,
        name: tokenInfo.name,
        displayValue: `${formattedBalance.toFixed(tokenInfo.decimals)} ${tokenInfo.symbol}`
      };
    } catch (error) {
      console.error('Error getting formatted balance:', error);
      throw error;
    }
  }
  
  // Portfolio balance checker
  async getPortfolioBalances(walletAddress, tokenList = null) {
    const tokens = tokenList || Object.entries(this.tokens);
    const balances = {};
    
    for (const [symbol, address] of tokens) {
      try {
        const balanceInfo = await this.getFormattedBalance(address, walletAddress);
        balances[symbol] = balanceInfo;
      } catch (error) {
        balances[symbol] = { error: error.message };
      }
    }
    
    return balances;
  }
  
  // Utility functions
  async callViewFunction(contractAddress, functionSelector, parameters = '') {
    const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        contract_address: contractAddress,
        function_selector: functionSelector,
        parameter: parameters,
        owner_address: contractAddress,
        visible: true
      })
    });
    
    const result = await response.json();
    
    if (result.result?.result && result.constant_result?.[0]) {
      return result.constant_result[0];
    }
    
    return null;
  }
  
  encodeAddress(address) {
    // Convert TRON Base58 address to hex parameter
    // This is a simplified version - use proper encoding in production
    return address.slice(1).toLowerCase().padStart(64, '0');
  }
  
  encodeUint256(value) {
    return BigInt(value).toString(16).padStart(64, '0');
  }
  
  parseString(hexResult) {
    if (!hexResult) return null;
    try {
      // Simple string parsing - use proper ABI decoding in production
      const bytes = hexResult.match(/.{2}/g) || [];
      return bytes.map(byte => String.fromCharCode(parseInt(byte, 16))).join('').replace(/\0/g, '');
    } catch {
      return null;
    }
  }
}

// Complete TRC20 Transfer Example
class TRC20TransferExample {
  constructor(apiKey) {
    this.tokenManager = new TRC20TokenManager(apiKey);
  }
  
  async transferUSDT(fromAddress, toAddress, amount, privateKey) {
    try {
      const usdtAddress = this.tokenManager.tokens.USDT;
      
      console.log('1. Checking USDT balance...');
      const balanceInfo = await this.tokenManager.getFormattedBalance(usdtAddress, fromAddress);
      console.log(`Balance: ${balanceInfo.displayValue}`);
      
      if (parseFloat(balanceInfo.formatted) < amount) {
        throw new Error(`Insufficient balance. Have: ${balanceInfo.formatted}, Need: ${amount}`);
      }
      
      console.log('2. Creating transfer transaction...');
      const amountInDecimals = amount * Math.pow(10, balanceInfo.decimals);
      const transferResult = await this.tokenManager.createTransfer(
        usdtAddress,
        fromAddress,
        toAddress,
        amountInDecimals.toString()
      );
      
      console.log(`3. Transaction created: ${transferResult.txId}`);
      console.log(`Energy required: ${transferResult.energyUsed}`);
      
      // In a real application, you would:
      // 4. Sign the transaction with the private key
      // 5. Broadcast the signed transaction
      // 6. Monitor for confirmation
      
      return {
        success: true,
        txId: transferResult.txId,
        transaction: transferResult.transaction,
        amount: amount,
        from: fromAddress,
        to: toAddress,
        token: 'USDT'
      };
      
    } catch (error) {
      console.error('USDT transfer failed:', error);
      throw error;
    }
  }
  
  async setupAllowanceAndTransfer(tokenAddress, ownerAddress, spenderAddress, amount, privateKey) {
    try {
      console.log('1. Checking current allowance...');
      const currentAllowance = await this.tokenManager.getAllowance(
        tokenAddress,
        ownerAddress,
        spenderAddress
      );
      
      if (BigInt(currentAllowance) < BigInt(amount)) {
        console.log('2. Setting up allowance...');
        const approvalResult = await this.tokenManager.createApproval(
          tokenAddress,
          ownerAddress,
          spenderAddress,
          amount
        );
        
        console.log(`Approval transaction: ${approvalResult.txId}`);
        // Sign and broadcast approval transaction
      }
      
      console.log('3. Creating transferFrom transaction...');
      const transferResult = await this.tokenManager.createTransferFrom(
        tokenAddress,
        spenderAddress,
        ownerAddress,
        'TDestinationAddress...',
        amount
      );
      
      console.log(`Transfer transaction: ${transferResult.txId}`);
      
      return {
        success: true,
        approval: approvalResult?.txId,
        transfer: transferResult.txId
      };
      
    } catch (error) {
      console.error('Allowance transfer failed:', error);
      throw error;
    }
  }
}

// Usage examples
(async () => {
  try {
    const tokenManager = new TRC20TokenManager('YOUR_API_KEY');
    
    // Check token balance
    const usdtBalance = await tokenManager.getFormattedBalance(
      tokenManager.tokens.USDT,
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN'
    );
    console.log('USDT Balance:', usdtBalance.displayValue);
    
    // Get portfolio
    const portfolio = await tokenManager.getPortfolioBalances('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN');
    console.log('Portfolio:', portfolio);
    
    // Transfer example
    const transferExample = new TRC20TransferExample('YOUR_API_KEY');
    const transferResult = await transferExample.transferUSDT(
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
      10, // 10 USDT
      'private_key_here'
    );
    console.log('Transfer result:', transferResult);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
from typing import Dict, List, Optional, Tuple

class TRC20TokenManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
        
        # Popular TRC20 contracts
        self.tokens = {
            'USDT': 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
            'USDC': 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8',
            'JST': 'TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9',
            'WTRX': 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR'
        }
    
    def get_balance(self, token_address: str, wallet_address: str) -> str:
        """Get token balance for address"""
        try:
            encoded_address = self._encode_address(wallet_address)
            
            response = requests.post(
                f"{self.base_url}/wallet/triggersmartcontract",
                headers=self.headers,
                json={
                    "contract_address": token_address,
                    "function_selector": "balanceOf(address)",
                    "parameter": encoded_address,
                    "owner_address": wallet_address,
                    "visible": True
                }
            )
            
            result = response.json()
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                balance_hex = result['constant_result'][0]
                return str(int(balance_hex, 16))
            
            return '0'
        except Exception as e:
            print(f"Error getting balance: {e}")
            raise
    
    def get_token_info(self, token_address: str) -> Dict:
        """Get token information (decimals, symbol, name)"""
        try:
            info = {}
            
            # Get decimals
            decimals_result = self._call_view_function(token_address, 'decimals()')
            info['decimals'] = int(decimals_result, 16) if decimals_result else 6
            
            # Get symbol
            symbol_result = self._call_view_function(token_address, 'symbol()')
            info['symbol'] = self._parse_string(symbol_result) or 'UNKNOWN'
            
            # Get name
            name_result = self._call_view_function(token_address, 'name()')
            info['name'] = self._parse_string(name_result) or 'Unknown Token'
            
            # Get total supply
            supply_result = self._call_view_function(token_address, 'totalSupply()')
            info['totalSupply'] = str(int(supply_result, 16)) if supply_result else '0'
            
            info['address'] = token_address
            
            return info
        except Exception as e:
            print(f"Error getting token info: {e}")
            raise
    
    def create_transfer(self, token_address: str, from_address: str, 
                       to_address: str, amount: str) -> Dict:
        """Create transfer transaction"""
        try:
            encoded_to = self._encode_address(to_address)
            encoded_amount = self._encode_uint256(amount)
            parameters = encoded_to + encoded_amount
            
            response = requests.post(
                f"{self.base_url}/wallet/triggersmartcontract",
                headers=self.headers,
                json={
                    "contract_address": token_address,
                    "function_selector": "transfer(address,uint256)",
                    "parameter": parameters,
                    "owner_address": from_address,
                    "visible": True
                }
            )
            
            result = response.json()
            
            if result.get('result', {}).get('result'):
                return {
                    'success': True,
                    'transaction': result['transaction'],
                    'energy_used': result.get('energy_used', 0),
                    'tx_id': result['transaction']['txID']
                }
            else:
                raise Exception(result.get('result', {}).get('message', 'Transfer creation failed'))
        except Exception as e:
            print(f"Error creating transfer: {e}")
            raise
    
    def create_approval(self, token_address: str, owner_address: str,
                       spender_address: str, amount: str) -> Dict:
        """Create approval transaction"""
        try:
            encoded_spender = self._encode_address(spender_address)
            encoded_amount = self._encode_uint256(amount)
            parameters = encoded_spender + encoded_amount
            
            response = requests.post(
                f"{self.base_url}/wallet/triggersmartcontract",
                headers=self.headers,
                json={
                    "contract_address": token_address,
                    "function_selector": "approve(address,uint256)",
                    "parameter": parameters,
                    "owner_address": owner_address,
                    "visible": True
                }
            )
            
            result = response.json()
            
            if result.get('result', {}).get('result'):
                return {
                    'success': True,
                    'transaction': result['transaction'],
                    'energy_used': result.get('energy_used', 0),
                    'tx_id': result['transaction']['txID']
                }
            else:
                raise Exception(result.get('result', {}).get('message', 'Approval creation failed'))
        except Exception as e:
            print(f"Error creating approval: {e}")
            raise
    
    def get_allowance(self, token_address: str, owner_address: str, spender_address: str) -> str:
        """Get allowance amount"""
        try:
            encoded_owner = self._encode_address(owner_address)
            encoded_spender = self._encode_address(spender_address)
            parameters = encoded_owner + encoded_spender
            
            response = requests.post(
                f"{self.base_url}/wallet/triggersmartcontract",
                headers=self.headers,
                json={
                    "contract_address": token_address,
                    "function_selector": "allowance(address,address)",
                    "parameter": parameters,
                    "owner_address": owner_address,
                    "visible": True
                }
            )
            
            result = response.json()
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                allowance_hex = result['constant_result'][0]
                return str(int(allowance_hex, 16))
            
            return '0'
        except Exception as e:
            print(f"Error getting allowance: {e}")
            raise
    
    def get_formatted_balance(self, token_address: str, wallet_address: str) -> Dict:
        """Get formatted balance with token info"""
        try:
            balance = self.get_balance(token_address, wallet_address)
            token_info = self.get_token_info(token_address)
            
            formatted_balance = float(balance) / (10 ** token_info['decimals'])
            
            return {
                'raw': balance,
                'formatted': formatted_balance,
                'decimals': token_info['decimals'],
                'symbol': token_info['symbol'],
                'name': token_info['name'],
                'display_value': f"{formatted_balance:.{token_info['decimals']}f} {token_info['symbol']}"
            }
        except Exception as e:
            print(f"Error getting formatted balance: {e}")
            raise
    
    def get_portfolio_balances(self, wallet_address: str, token_list: List[Tuple[str, str]] = None) -> Dict:
        """Get balances for multiple tokens"""
        if token_list is None:
            token_list = list(self.tokens.items())
        
        balances = {}
        
        for symbol, address in token_list:
            try:
                balance_info = self.get_formatted_balance(address, wallet_address)
                balances[symbol] = balance_info
            except Exception as e:
                balances[symbol] = {'error': str(e)}
        
        return balances
    
    def _call_view_function(self, contract_address: str, function_selector: str, parameters: str = '') -> Optional[str]:
        """Call view function on contract"""
        response = requests.post(
            f"{self.base_url}/wallet/triggersmartcontract",
            headers=self.headers,
            json={
                "contract_address": contract_address,
                "function_selector": function_selector,
                "parameter": parameters,
                "owner_address": contract_address,
                "visible": True
            }
        )
        
        result = response.json()
        
        if result.get('result', {}).get('result') and result.get('constant_result'):
            return result['constant_result'][0]
        
        return None
    
    def _encode_address(self, address: str) -> str:
        """Encode TRON address for contract parameters"""
        # Simplified encoding - use proper library in production
        return address[1:].lower().zfill(64)
    
    def _encode_uint256(self, value: str) -> str:
        """Encode uint256 for contract parameters"""
        return format(int(value), '064x')
    
    def _parse_string(self, hex_result: str) -> Optional[str]:
        """Parse string from hex result"""
        if not hex_result:
            return None
        
        try:
            # Simple string parsing - use proper ABI decoding in production
            bytes_data = bytes.fromhex(hex_result)
            return bytes_data.decode('utf-8').rstrip('\x00')
        except:
            return None

class TRC20TransferExample:
    def __init__(self, api_key: str):
        self.token_manager = TRC20TokenManager(api_key)
    
    def transfer_usdt(self, from_address: str, to_address: str, amount: float, private_key: str) -> Dict:
        """Complete USDT transfer example"""
        try:
            usdt_address = self.token_manager.tokens['USDT']
            
            print('1. Checking USDT balance...')
            balance_info = self.token_manager.get_formatted_balance(usdt_address, from_address)
            print(f"Balance: {balance_info['display_value']}")
            
            if balance_info['formatted'] < amount:
                raise Exception(f"Insufficient balance. Have: {balance_info['formatted']}, Need: {amount}")
            
            print('2. Creating transfer transaction...')
            amount_in_decimals = int(amount * (10 ** balance_info['decimals']))
            transfer_result = self.token_manager.create_transfer(
                usdt_address,
                from_address,
                to_address,
                str(amount_in_decimals)
            )
            
            print(f"3. Transaction created: {transfer_result['tx_id']}")
            print(f"Energy required: {transfer_result['energy_used']}")
            
            # In a real application, you would:
            # 4. Sign the transaction with the private key
            # 5. Broadcast the signed transaction
            # 6. Monitor for confirmation
            
            return {
                'success': True,
                'tx_id': transfer_result['tx_id'],
                'transaction': transfer_result['transaction'],
                'amount': amount,
                'from': from_address,
                'to': to_address,
                'token': 'USDT'
            }
            
        except Exception as e:
            print(f"USDT transfer failed: {e}")
            raise
    
    def setup_allowance_and_transfer(self, token_address: str, owner_address: str,
                                   spender_address: str, amount: str, private_key: str) -> Dict:
        """Setup allowance and create transferFrom transaction"""
        try:
            print('1. Checking current allowance...')
            current_allowance = self.token_manager.get_allowance(
                token_address,
                owner_address,
                spender_address
            )
            
            approval_result = None
            if int(current_allowance) < int(amount):
                print('2. Setting up allowance...')
                approval_result = self.token_manager.create_approval(
                    token_address,
                    owner_address,
                    spender_address,
                    amount
                )
                print(f"Approval transaction: {approval_result['tx_id']}")
                # Sign and broadcast approval transaction
            
            print('3. Creating transferFrom transaction...')
            # Create transferFrom transaction parameters
            encoded_from = self.token_manager._encode_address(owner_address)
            encoded_to = self.token_manager._encode_address('TDestinationAddress...')
            encoded_amount = self.token_manager._encode_uint256(amount)
            parameters = encoded_from + encoded_to + encoded_amount
            
            response = requests.post(
                f"{self.token_manager.base_url}/wallet/triggersmartcontract",
                headers=self.token_manager.headers,
                json={
                    "contract_address": token_address,
                    "function_selector": "transferFrom(address,address,uint256)",
                    "parameter": parameters,
                    "owner_address": spender_address,
                    "visible": True
                }
            )
            
            transfer_result = response.json()
            print(f"Transfer transaction: {transfer_result['transaction']['txID']}")
            
            return {
                'success': True,
                'approval': approval_result['tx_id'] if approval_result else None,
                'transfer': transfer_result['transaction']['txID']
            }
            
        except Exception as e:
            print(f"Allowance transfer failed: {e}")
            raise

# Usage examples
if __name__ == "__main__":
    token_manager = TRC20TokenManager('YOUR_API_KEY')
    
    try:
        # Check token balance
        usdt_balance = token_manager.get_formatted_balance(
            token_manager.tokens['USDT'],
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN'
        )
        print(f"USDT Balance: {usdt_balance['display_value']}")
        
        # Get portfolio
        portfolio = token_manager.get_portfolio_balances('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN')
        print("Portfolio:")
        for token, info in portfolio.items():
            if 'error' in info:
                print(f"  {token}: Error - {info['error']}")
            else:
                print(f"  {token}: {info['display_value']}")
        
        # Transfer example
        transfer_example = TRC20TransferExample('YOUR_API_KEY')
        transfer_result = transfer_example.transfer_usdt(
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            10.0,  # 10 USDT
            'private_key_here'
        )
        print(f"Transfer result: {transfer_result}")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Best Practices

### 1. Error Handling

```javascript
async function safeTokenTransfer(tokenAddress, fromAddress, toAddress, amount) {
  try {
    // 1. Validate inputs
    if (!isValidTronAddress(fromAddress) || !isValidTronAddress(toAddress)) {
      throw new Error('Invalid address format');
    }
    
    if (amount <= 0) {
      throw new Error('Amount must be positive');
    }
    
    // 2. Check token exists
    const tokenInfo = await getTokenInfo(tokenAddress);
    if (!tokenInfo) {
      throw new Error('Token contract not found');
    }
    
    // 3. Check balance
    const balance = await getTokenBalance(tokenAddress, fromAddress);
    const amountInDecimals = amount * Math.pow(10, tokenInfo.decimals);
    
    if (parseFloat(balance) < amountInDecimals) {
      throw new Error('Insufficient token balance');
    }
    
    // 4. Check energy/bandwidth
    const resourceCheck = await checkResourcesForTransfer(fromAddress);
    if (!resourceCheck.canExecute) {
      throw new Error(`Insufficient resources: ${resourceCheck.reason}`);
    }
    
    // 5. Create transaction
    const transferResult = await createTokenTransfer(
      tokenAddress,
      fromAddress,
      toAddress,
      amountInDecimals.toString()
    );
    
    return {
      success: true,
      transaction: transferResult,
      estimatedCost: resourceCheck.estimatedCost
    };
    
  } catch (error) {
    return {
      success: false,
      error: error.message,
      code: error.code || 'UNKNOWN_ERROR'
    };
  }
}
```

### 2. Gas Optimization

```javascript
class TRC20GasOptimizer {
  async optimizeTransfer(tokenAddress, fromAddress, toAddress, amount) {
    // 1. Estimate energy cost
    const energyEstimate = await estimateEnergyForTransfer(tokenAddress, fromAddress, amount);
    
    // 2. Check if user has enough staked energy
    const resources = await getAccountResources(fromAddress);
    const availableEnergy = resources.EnergyLimit - resources.EnergyUsed;
    
    if (availableEnergy >= energyEstimate) {
      return {
        strategy: 'use_staked_energy',
        cost: 0,
        recommendation: 'Transaction will execute for free'
      };
    }
    
    // 3. Calculate different cost strategies
    const strategies = [
      {
        name: 'Pay with TRX',
        cost: energyEstimate * 0.00014,
        description: 'Pay TRX for energy consumption'
      },
      {
        name: 'Rent energy',
        cost: energyEstimate * 0.0001,
        description: 'Rent energy from third-party (30% cheaper)'
      },
      {
        name: 'Stake TRX',
        cost: energyEstimate / 4000,
        description: 'Stake TRX for reusable energy (best for frequent use)'
      }
    ];
    
    return {
      energyRequired: energyEstimate,
      strategies: strategies.sort((a, b) => a.cost - b.cost),
      recommendation: strategies[0]
    };
  }
}
```

### 3. Transaction Monitoring

```javascript
class TRC20TransactionMonitor {
  async monitorTransfer(txId, expectedAmount, expectedRecipient, tokenAddress) {
    const timeout = 60000; // 1 minute
    const checkInterval = 3000; // 3 seconds
    const startTime = Date.now();
    
    while (Date.now() - startTime < timeout) {
      try {
        const txDetails = await getTransactionById(txId);
        
        if (txDetails.blockNumber) {
          // Transaction confirmed, verify details
          const verification = await this.verifyTransfer(
            txDetails,
            expectedAmount,
            expectedRecipient,
            tokenAddress
          );
          
          return {
            confirmed: true,
            verified: verification.success,
            details: txDetails,
            verification: verification
          };
        }
        
        console.log('Waiting for confirmation...');
        await new Promise(resolve => setTimeout(resolve, checkInterval));
        
      } catch (error) {
        console.error('Monitoring error:', error);
      }
    }
    
    return {
      confirmed: false,
      timeout: true,
      message: 'Transaction confirmation timeout'
    };
  }
  
  async verifyTransfer(txDetails, expectedAmount, expectedRecipient, tokenAddress) {
    // Verify transaction called the correct contract
    const contract = txDetails.raw_data?.contract?.[0];
    if (contract?.parameter?.value?.contract_address !== tokenAddress) {
      return { success: false, reason: 'Wrong contract called' };
    }
    
    // Decode transfer parameters (simplified)
    // In production, use proper ABI decoding
    const data = contract.parameter.value.data;
    if (!data.startsWith('a9059cbb')) { // transfer function selector
      return { success: false, reason: 'Not a transfer call' };
    }
    
    return {
      success: true,
      verified: true,
      message: 'Transfer verified successfully'
    };
  }
}
```

## Security Considerations

1. **Validate Addresses** - Always validate TRON addresses before transactions
2. **Check Token Contracts** - Verify token contract addresses against known lists
3. **Amount Validation** - Validate amounts and handle decimal precision correctly
4. **Resource Checks** - Ensure sufficient energy/bandwidth before transactions
5. **Private Key Security** - Never expose private keys in client-side code
6. **Transaction Limits** - Implement reasonable limits for user protection

## Common Pitfalls

1. **Decimal Precision** - Always account for token decimals when calculating amounts
2. **Address Format** - Use correct encoding for contract parameters
3. **Gas Estimation** - Factor in energy costs for smart contract calls
4. **Approval First** - Remember to approve before transferFrom operations
5. **Network Congestion** - Handle transaction delays and failures gracefully

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/broadcasthex - Broadcast Raw Transaction...

# wallet/broadcasthex - Broadcast Raw Transaction...

Broadcast a signed transaction in hexadecimal format to the TRON network.

## Endpoint

```
POST /wallet/broadcasthex
```

## Request Parameters

- `transaction` (`string, required`): Required parameter: Signed transaction in hexadecimal format

## Request Example

```bash
# Broadcast signed transaction hex
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasthex \
      -H "Content-Type: application/json" \
      -d '{
        "transaction": "0a85010a0227f02208c89fc99c0f53e5c940c8fbe4f62d5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541e552f6487911a8245ef73158f8eb5dd3343dc2121541d1e7a6bc354106cb410e65ff8b181c600ff1429218c0843d70f5bce4f62d124138cb1c9a31f44e0e929e44e3f6e4e33a056eb92e4e4c94db2e5892a2834ae0ed8010e1bd7bc5cf5fa100"
      }'

    # Check result with jq
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasthex \
      -H "Content-Type: application/json" \
      -d '{
        "transaction": "YOUR_SIGNED_TX_HEX"
      }' | jq '.result, .txid, .message'
```

## Response Fields

- `result` (`OBJECT, required`): `result` - Boolean indicating success `code` - Error code if failed `message` - Error message if failed `txid` - Transaction ID if successful

## Successful Response

```json
{
  "result": true,
  "txid": "7c2d4206c03a883dd9066d6c839d0deaef32dc5a0d9b15f6d06e506906c90332"
}
```

## Important Notes

### Transaction Format

1. **Must be signed**: Transaction must be properly signed before broadcasting
2. **Hex encoded**: Entire signed transaction must be hex encoded
3. **Valid expiration**: Transaction must not be expired
4. **Proper structure**: Must follow TRON transaction format

### Common Use Cases

- Broadcasting pre-signed transactions
- Offline transaction signing
- Multi-signature transactions
- Hardware wallet integrations

## Implementation Examples

cURL
JavaScript
Python

```bash
# Broadcast signed transaction hex
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasthex \
  -H "Content-Type: application/json" \
  -d '{
    "transaction": "0a85010a0227f02208c89fc99c0f53e5c940c8fbe4f62d5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541e552f6487911a8245ef73158f8eb5dd3343dc2121541d1e7a6bc354106cb410e65ff8b181c600ff1429218c0843d70f5bce4f62d124138cb1c9a31f44e0e929e44e3f6e4e33a056eb92e4e4c94db2e5892a2834ae0ed8010e1bd7bc5cf5fa100"
  }'

# Check result with jq
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasthex \
  -H "Content-Type: application/json" \
  -d '{
    "transaction": "YOUR_SIGNED_TX_HEX"
  }' | jq '.result, .txid, .message'
```

```javascript
// Broadcast signed transaction hex
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasthex', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    transaction: '0a85010a0227f02208c89fc99c0f53e5c940c8fbe4f62d5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541e552f6487911a8245ef73158f8eb5dd3343dc2121541d1e7a6bc354106cb410e65ff8b181c600ff1429218c0843d70f5bce4f62d124138cb1c9a31f44e0e929e44e3f6e4e33a056eb92e4e4c94db2e5892a2834ae0ed8010e1bd7bc5cf5fa100'
  }),
});

const result = await response.json();

if (result.result) {
  console.log('Transaction broadcast successfully!');
  console.log('Transaction ID:', result.txid);
} else {
  console.error('Broadcast failed:', result.message);
  console.error('Error code:', result.code);
}

// Function to prepare and broadcast transaction
async function broadcastSignedTransaction(signedTxHex) {
  try {
    const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasthex', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        transaction: signedTxHex
      }),
    });

    const result = await response.json();
    
    if (result.result) {
      return {
        success: true,
        txid: result.txid,
        message: 'Transaction broadcast successfully'
      };
    } else {
      return {
        success: false,
        code: result.code,
        message: result.message || 'Unknown error'
      };
    }
  } catch (error) {
    return {
      success: false,
      message: `Network error: ${error.message}`
    };
  }
}

// Example: Offline signing workflow
async function offlineSigningWorkflow() {
  // Step 1: Create transaction offline
  const unsignedTx = {
    // Transaction details created offline
    raw_data: {
      contract: [...],
      expiration: Date.now() + 60000,
      timestamp: Date.now()
    }
  };
  
  // Step 2: Sign transaction offline (using private key)
  // This would typically be done on an air-gapped machine
  const signedTx = signTransaction(unsignedTx, privateKey);
  
  // Step 3: Convert to hex
  const txHex = Buffer.from(JSON.stringify(signedTx)).toString('hex');
  
  // Step 4: Broadcast online
  const result = await broadcastSignedTransaction(txHex);
  
  if (result.success) {
    console.log(`Transaction broadcast: ${result.txid}`);
  } else {
    console.error(`Broadcast failed: ${result.message}`);
  }
}
```

```python
import requests
import json

def broadcast_hex_transaction(hex_transaction, api_key):
    """Broadcast a signed transaction in hex format"""
    
    url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}/wallet/broadcasthex"
    
    payload = {
        "transaction": hex_transaction
    }
    
    response = requests.post(url, json=payload)
    result = response.json()
    
    if result.get('result'):
        return {
            'success': True,
            'txid': result.get('txid'),
            'message': 'Transaction broadcast successfully'
        }
    else:
        return {
            'success': False,
            'code': result.get('code'),
            'message': result.get('message', 'Unknown error')
        }

# Example usage
def main():
    api_key = "YOUR_API_KEY"
    
    # Example signed transaction hex (replace with actual signed tx)
    signed_tx_hex = "0a85010a0227f02208c89fc99c0f53e5c940c8fbe4f62d5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541e552f6487911a8245ef73158f8eb5dd3343dc2121541d1e7a6bc354106cb410e65ff8b181c600ff1429218c0843d70f5bce4f62d124138cb1c9a31f44e0e929e44e3f6e4e33a056eb92e4e4c94db2e5892a2834ae0ed8010e1bd7bc5cf5fa100"
    
    # Broadcast transaction
    result = broadcast_hex_transaction(signed_tx_hex, api_key)
    
    if result['success']:
        print(f"✅ Transaction broadcast successfully!")
        print(f"Transaction ID: {result['txid']}")
    else:
        print(f"❌ Broadcast failed!")
        print(f"Error: {result['message']}")
        if result.get('code'):
            print(f"Error code: {result['code']}")

# Offline signing example
def offline_signing_example():
    """Example workflow for offline transaction signing"""
    
    # Step 1: Prepare transaction data offline
    transaction_data = {
        "to": "TRecipientAddress...",
        "amount": 1000000,  # 1 TRX in SUN
        "from": "TSenderAddress..."
    }
    
    # Step 2: Create and sign transaction offline
    # (This would be done on an air-gapped machine)
    # signed_tx = sign_transaction_offline(transaction_data, private_key)
    
    # Step 3: Convert to hex
    # tx_hex = signed_tx.hex()
    
    # Step 4: Transfer hex to online machine and broadcast
    # result = broadcast_hex_transaction(tx_hex, "YOUR_API_KEY")
    
    print("Offline signing workflow completed")

# Multi-signature example
def multisig_broadcast_example():
    """Example for broadcasting multi-signature transaction"""
    
    api_key = "YOUR_API_KEY"
    
    # After collecting all required signatures offline
    fully_signed_tx_hex = "..." # Hex of fully signed multi-sig transaction
    
    result = broadcast_hex_transaction(fully_signed_tx_hex, api_key)
    
    if result['success']:
        print(f"Multi-sig transaction broadcast: {result['txid']}")
    else:
        print(f"Multi-sig broadcast failed: {result['message']}")

if __name__ == "__main__":
    main()
```

## Error Codes

| Code                           | Description                   | Solution                                      |
| ------------------------------ | ----------------------------- | --------------------------------------------- |
| `TRANSACTION_EXPIRATION_ERROR` | Transaction has expired       | Create new transaction with longer expiration |
| `DUP_TRANSACTION_ERROR`        | Transaction already broadcast | Transaction already in mempool or confirmed   |
| `TAPOS_ERROR`                  | Invalid block reference       | Update reference block in transaction         |
| `TOO_BIG_TRANSACTION_ERROR`    | Transaction size too large    | Reduce transaction data size                  |
| `TRANSACTION_SIGN_ERROR`       | Invalid signature             | Verify signature is correct                   |
| `ACCOUNT_NOT_EXIST_ERROR`      | Account doesn't exist         | Ensure account is activated                   |
| `NOT_ENOUGH_BANDWIDTH`         | Insufficient bandwidth        | Stake TRX for bandwidth or burn TRX           |
| `NOT_ENOUGH_ENERGY`            | Insufficient energy           | Stake TRX for energy or burn TRX              |

## Advanced Usage

```javascript
class TransactionBroadcaster {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }

  // Broadcast with retry logic
  async broadcastWithRetry(hexTx, maxRetries = 3) {
    let lastError;
    
    for (let i = 0; i < maxRetries; i++) {
      try {
        const response = await fetch(`${this.baseUrl}/wallet/broadcasthex`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ transaction: hexTx })
        });
        
        const result = await response.json();
        
        if (result.result) {
          return {
            success: true,
            txid: result.txid,
            attempts: i + 1
          };
        }
        
        // Check if error is retryable
        if (result.code === 'DUP_TRANSACTION_ERROR') {
          // Transaction already broadcast, consider it success
          return {
            success: true,
            message: 'Transaction already broadcast',
            attempts: i + 1
          };
        }
        
        if (result.code === 'TRANSACTION_EXPIRATION_ERROR') {
          // Don't retry expired transactions
          throw new Error('Transaction expired, cannot retry');
        }
        
        lastError = result;
        
        // Wait before retry
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        
      } catch (error) {
        lastError = error;
      }
    }
    
    return {
      success: false,
      error: lastError,
      attempts: maxRetries
    };
  }

  // Validate hex transaction before broadcasting
  validateHexTransaction(hexTx) {
    try {
      // Check if valid hex
      if (!/^[0-9a-fA-F]+$/.test(hexTx)) {
        return { valid: false, error: 'Invalid hex format' };
      }
      
      // Check minimum length (rough estimate)
      if (hexTx.length < 100) {
        return { valid: false, error: 'Transaction too short' };
      }
      
      // Check maximum length
      if (hexTx.length > 65536 * 2) { // 64KB in hex
        return { valid: false, error: 'Transaction too large' };
      }
      
      return { valid: true };
      
    } catch (error) {
      return { valid: false, error: error.message };
    }
  }

  // Batch broadcast multiple transactions
  async batchBroadcast(hexTransactions) {
    const results = [];
    
    for (const hexTx of hexTransactions) {
      // Validate before broadcasting
      const validation = this.validateHexTransaction(hexTx);
      
      if (!validation.valid) {
        results.push({
          success: false,
          error: validation.error
        });
        continue;
      }
      
      // Broadcast with retry
      const result = await this.broadcastWithRetry(hexTx);
      results.push(result);
      
      // Small delay between broadcasts
      await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    return results;
  }
}

// Example usage
async function advancedBroadcast() {
  const broadcaster = new TransactionBroadcaster('YOUR_API_KEY');
  
  // Single transaction with retry
  const txHex = 'YOUR_SIGNED_TX_HEX';
  const result = await broadcaster.broadcastWithRetry(txHex);
  
  if (result.success) {
    console.log(`Transaction broadcast after ${result.attempts} attempts`);
    console.log(`TX ID: ${result.txid}`);
  } else {
    console.error('Broadcast failed:', result.error);
  }
  
  // Batch broadcast
  const transactions = [
    'SIGNED_TX_HEX_1',
    'SIGNED_TX_HEX_2',
    'SIGNED_TX_HEX_3'
  ];
  
  const batchResults = await broadcaster.batchBroadcast(transactions);
  
  batchResults.forEach((result, index) => {
    if (result.success) {
      console.log(`TX ${index + 1}: Success - ${result.txid}`);
    } else {
      console.log(`TX ${index + 1}: Failed - ${result.error}`);
    }
  });
}
```

## Best Practices

### 1. **Validation**

- Validate hex format before broadcasting
- Check transaction expiration
- Verify sufficient resources

### 2. **Error Handling**

- Implement retry logic for network errors
- Handle duplicate transaction errors gracefully
- Log all broadcast attempts

### 3. **Security**

- Never expose private keys
- Use secure channels for hex transmission
- Verify transaction details before broadcasting

### 4. **Optimization**

- Batch transactions when possible
- Monitor network congestion
- Set appropriate expiration times

## Use Cases

- **Offline Signing**: Sign transactions on air-gapped devices
- **Multi-Signature**: Collect signatures offline, broadcast online
- **Hardware Wallets**: Integrate with Ledger, Trezor, etc.
- **Transaction Relaying**: Relay pre-signed transactions
- **Automated Systems**: Broadcast pre-prepared transactions

## Related Methods

- [wallet/broadcasttransaction](https://www.dwellir.com/docs/tron/wallet-broadcasttransaction) - Broadcast JSON transaction
- [wallet/gettransactionbyid](https://www.dwellir.com/docs/tron/wallet-gettransactionbyid) - Check transaction status
- [wallet/gettransactioninfobyid](https://www.dwellir.com/docs/tron/wallet-gettransactioninfobyid) - Get transaction receipt

---

## wallet/broadcasttransaction - Broadcast TRON Tr...

# wallet/broadcasttransaction - Broadcast TRON Tr...

**Dwellir's TRON endpoints** broadcast transactions to the network in under 100ms with real-time confirmation tracking.
Get instant feedback on transaction success and network inclusion.

[Start broadcasting now](https://dashboard.dwellir.com/register)

Broadcasts a signed transaction to the TRON network for execution. This is the final step after creating and signing a transaction.

## When to Use This Method

`wallet/broadcasttransaction` is essential for:

- **Transaction Execution** - Submit signed transactions to the network
- **Payment Processing** - Complete payment transactions in real-time
- **Smart Contract Calls** - Execute signed contract interactions
- **Multi-Signature Operations** - Broadcast fully-signed multi-sig transactions
- **Batch Processing** - Submit multiple transactions efficiently

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "txID": "94eea63bb6774c8fc4f4c9d1b62c1e8c2f7c8c2e4d3a2b1c0d9e8f7a6b5c4d3e2f1",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "amount": 1000000,
            "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
            "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
          },
          "type_url": "type.googleapis.com/protocol.TransferContract"
        },
        "type": "TransferContract"
      }
    ],
    "ref_block_bytes": "4a7b",
    "ref_block_hash": "e15e44aa73bd9e15",
    "expiration": 1734567890000,
    "timestamp": 1734567830000
  },
  "signature": ["c8f8f8e8d8c8b8a898887878686858484838281807060504030201"]
}
```

## Response Fields

- `result` (`OBJECT, required`): `result` - Boolean indicating broadcast success `txid` - Transaction ID (if successful) `code` - Error code (if failed) `message` - Error message (if failed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Error Responses

### Error 1

- Code: `CONTRACT_VALIDATE_ERROR`
- Description: Transaction validation failed

### Error 2

- Code: `BANDWIDTH_ERROR`
- Description: Insufficient bandwidth

### Error 3

- Code: `ENERGY_ERROR`
- Description: Insufficient energy

### Error 4

- Code: `SIGNATURE_ERROR`
- Description: Invalid signature

### Error 5

- Code: `EXPIRED_ERROR`
- Description: Transaction expired

### Error 6

- Code: `SERVER_BUSY`
- Description: Network congestion

## Implementation Examples

cURL
JavaScript
Python

```bash
# Basic transaction broadcast
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasttransaction" \
  -H "Content-Type: application/json" \
  -d '{
    "txID": "94eea63bb6774c8fc4f4c9d1b62c1e8c2f7c8c2e4d3a2b1c0d9e8f7a6b5c4d3e2f1",
    "raw_data": {
      "contract": [{
        "parameter": {
          "value": {
            "amount": 1000000,
            "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
            "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
          },
          "type_url": "type.googleapis.com/protocol.TransferContract"
        },
        "type": "TransferContract"
      }],
      "ref_block_bytes": "4a7b",
      "ref_block_hash": "e15e44aa73bd9e15",
      "expiration": 1734567890000,
      "timestamp": 1734567830000
    },
    "signature": ["c8f8f8e8d8c8b8a898887878686858484838281807060504030201"]
  }'

# Broadcast and check result
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/broadcasttransaction" \
  -H "Content-Type: application/json" \
  -d @signed_transaction.json | jq '{
    success: .result,
    txid: .txid,
    error: .message
  }'

# Script with retry logic
#!/bin/bash
API_KEY="YOUR_API_KEY"
SIGNED_TX_FILE="signed_transaction.json"
MAX_RETRIES=3

broadcast_with_retry() {
  local attempt=1
  
  while [ $attempt -le $MAX_RETRIES ]; do
    echo "Broadcasting transaction (attempt $attempt/$MAX_RETRIES)..."
    
    RESULT=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/broadcasttransaction" \
      -H "Content-Type: application/json" \
      -d @"$SIGNED_TX_FILE")
    
    SUCCESS=$(echo "$RESULT" | jq -r '.result // false')
    
    if [ "$SUCCESS" = "true" ]; then
      TXID=$(echo "$RESULT" | jq -r '.txid')
      echo "✓ Transaction broadcast successful: $TXID"
      return 0
    else
      ERROR=$(echo "$RESULT" | jq -r '.message // "Unknown error"')
      echo "✗ Attempt $attempt failed: $ERROR"
      
      if [ $attempt -eq $MAX_RETRIES ]; then
        echo "Transaction broadcast failed after $MAX_RETRIES attempts"
        return 1
      fi
      
      # Exponential backoff
      DELAY=$((2 ** (attempt - 1)))
      echo "Waiting ${DELAY}s before retry..."
      sleep $DELAY
    fi
    
    ((attempt++))
  done
}

# Check transaction confirmation
check_confirmation() {
  local txid=$1
  local timeout=${2:-30}
  local start_time=$(date +%s)
  
  echo "Waiting for confirmation of $txid..."
  
  while true; do
    current_time=$(date +%s)
    elapsed=$((current_time - start_time))
    
    if [ $elapsed -ge $timeout ]; then
      echo "Confirmation timeout after ${timeout}s"
      return 1
    fi
    
    TX_INFO=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/gettransactionbyid" \
      -H "Content-Type: application/json" \
      -d "{\"value\": \"$txid\", \"visible\": true}")
    
    BLOCK_NUM=$(echo "$TX_INFO" | jq -r '.blockNumber // null')
    
    if [ "$BLOCK_NUM" != "null" ]; then
      echo "✓ Transaction confirmed in block $BLOCK_NUM"
      return 0
    fi
    
    echo "Checking confirmation... (${elapsed}s elapsed)"
    sleep 3
  done
}

# Batch broadcasting script
batch_broadcast() {
  local tx_files=("$@")
  local successful=0
  local failed=0
  
  echo "Broadcasting ${#tx_files[@]} transactions..."
  
  for tx_file in "${tx_files[@]}"; do
    echo "Processing $tx_file..."
    
    if broadcast_with_retry "$tx_file"; then
      ((successful++))
    else
      ((failed++))
    fi
    
    # Rate limiting
    sleep 0.1
  done
  
  echo "Batch complete: $successful successful, $failed failed"
}

# Usage
if [ "$1" = "single" ]; then
  broadcast_with_retry && check_confirmation "$(echo "$RESULT" | jq -r '.txid')"
elif [ "$1" = "batch" ]; then
  shift
  batch_broadcast "$@"
else
  echo "Usage: $0 {single|batch} [tx_files...]"
fi
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Broadcast a signed transaction
async function broadcastTransaction(signedTransaction) {
  const response = await fetch(`${TRON_API}/wallet/broadcasttransaction`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(signedTransaction)
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Enhanced broadcast with monitoring and retry logic
async function broadcastWithMonitoring(signedTransaction, options = {}) {
  const {
    maxRetries = 3,
    retryDelay = 1000,
    confirmationTimeout = 30000
  } = options;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`Broadcasting transaction (attempt ${attempt}/${maxRetries})...`);
      
      const result = await broadcastTransaction(signedTransaction);
      
      if (result.result) {
        console.log(`✓ Transaction broadcast successful: ${result.txid}`);
        
        // Optional: Wait for confirmation
        if (options.waitForConfirmation) {
          const confirmation = await waitForConfirmation(result.txid, confirmationTimeout);
          return { ...result, confirmation };
        }
        
        return result;
      } else {
        throw new Error(`Broadcast failed: ${result.message || 'Unknown error'}`);
      }
    } catch (error) {
      console.log(`✗ Attempt ${attempt} failed:`, error.message);
      
      if (attempt === maxRetries) {
        throw new Error(`Transaction broadcast failed after ${maxRetries} attempts: ${error.message}`);
      }
      
      // Exponential backoff
      await new Promise(resolve => setTimeout(resolve, retryDelay * Math.pow(2, attempt - 1)));
    }
  }
}

// Wait for transaction confirmation
async function waitForConfirmation(txId, timeout = 30000) {
  const startTime = Date.now();
  const checkInterval = 3000; // Check every 3 seconds
  
  while (Date.now() - startTime < timeout) {
    try {
      const txInfo = await getTransactionInfo(txId);
      
      if (txInfo && txInfo.blockNumber) {
        return {
          confirmed: true,
          blockNumber: txInfo.blockNumber,
          confirmationTime: Date.now() - startTime,
          fee: txInfo.fee || 0
        };
      }
    } catch (error) {
      console.log('Checking confirmation...', error.message);
    }
    
    await new Promise(resolve => setTimeout(resolve, checkInterval));
  }
  
  return {
    confirmed: false,
    timeout: true,
    message: 'Transaction confirmation timeout'
  };
}

// Get transaction information for confirmation
async function getTransactionInfo(txId) {
  const response = await fetch(`${TRON_API}/wallet/gettransactionbyid`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ value: txId, visible: true })
  });
  
  return await response.json();
}

// Batch transaction broadcasting
async function broadcastBatch(signedTransactions, options = {}) {
  const { 
    concurrency = 5,
    delayBetween = 100 
  } = options;
  
  const results = [];
  
  // Process in chunks to respect rate limits
  for (let i = 0; i < signedTransactions.length; i += concurrency) {
    const chunk = signedTransactions.slice(i, i + concurrency);
    
    const chunkPromises = chunk.map(async (tx, index) => {
      try {
        // Stagger requests slightly
        await new Promise(resolve => setTimeout(resolve, index * delayBetween));
        
        const result = await broadcastWithMonitoring(tx);
        return {
          success: true,
          txId: tx.txID,
          result: result,
          index: i + index
        };
      } catch (error) {
        return {
          success: false,
          txId: tx.txID,
          error: error.message,
          index: i + index
        };
      }
    });
    
    const chunkResults = await Promise.allSettled(chunkPromises);
    results.push(...chunkResults.map(r => r.status === 'fulfilled' ? r.value : r.reason));
    
    // Delay between chunks
    if (i + concurrency < signedTransactions.length) {
      await new Promise(resolve => setTimeout(resolve, delayBetween * concurrency));
    }
  }
  
  return {
    total: signedTransactions.length,
    successful: results.filter(r => r.success).length,
    failed: results.filter(r => !r.success).length,
    results: results
  };
}

// Complete transaction flow example
async function sendTRXTransaction(fromAddress, toAddress, amount, privateKey) {
  try {
    // Step 1: Create transaction
    console.log('Creating transaction...');
    const transaction = await createTransaction(fromAddress, toAddress, amount);
    
    // Step 2: Sign transaction (simplified - use proper signing library)
    console.log('Signing transaction...');
    const signedTransaction = await signTransaction(transaction, privateKey);
    
    // Step 3: Broadcast transaction
    console.log('Broadcasting transaction...');
    const result = await broadcastWithMonitoring(signedTransaction, {
      waitForConfirmation: true,
      maxRetries: 3
    });
    
    console.log('Transaction completed:', result);
    return result;
    
  } catch (error) {
    console.error('Transaction failed:', error.message);
    throw error;
  }
}

// Usage examples
(async () => {
  try {
    // Single transaction broadcast
    const signedTx = {
      // ... signed transaction object
    };
    
    const result = await broadcastWithMonitoring(signedTx, {
      waitForConfirmation: true,
      maxRetries: 3
    });
    console.log('Broadcast result:', result);
    
    // Batch broadcasting
    const signedTransactions = [
      // ... array of signed transactions
    ];
    
    const batchResult = await broadcastBatch(signedTransactions, {
      concurrency: 3,
      delayBetween: 200
    });
    console.log(`Batch complete: ${batchResult.successful}/${batchResult.total} successful`);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import time
import asyncio
import aiohttp
from typing import Dict, List, Optional

class TronBroadcaster:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def broadcast_transaction(self, signed_transaction: Dict) -> Dict:
        """Broadcast a signed transaction to TRON network"""
        url = f"{self.base_url}/wallet/broadcasttransaction"
        
        response = requests.post(url, headers=self.headers, json=signed_transaction)
        response.raise_for_status()
        
        return response.json()
    
    def broadcast_with_monitoring(self, signed_transaction: Dict, 
                                 max_retries: int = 3,
                                 retry_delay: int = 1000,
                                 wait_for_confirmation: bool = False,
                                 confirmation_timeout: int = 30000) -> Dict:
        """Broadcast transaction with retry logic and optional confirmation"""
        
        for attempt in range(1, max_retries + 1):
            try:
                print(f"Broadcasting transaction (attempt {attempt}/{max_retries})...")
                
                result = self.broadcast_transaction(signed_transaction)
                
                if result.get('result'):
                    print(f"✓ Transaction broadcast successful: {result.get('txid')}")
                    
                    # Optional: Wait for confirmation
                    if wait_for_confirmation:
                        confirmation = self.wait_for_confirmation(
                            result['txid'], 
                            confirmation_timeout
                        )
                        result['confirmation'] = confirmation
                    
                    return result
                else:
                    raise Exception(f"Broadcast failed: {result.get('message', 'Unknown error')}")
                    
            except Exception as e:
                print(f"✗ Attempt {attempt} failed: {str(e)}")
                
                if attempt == max_retries:
                    raise Exception(f"Transaction broadcast failed after {max_retries} attempts: {str(e)}")
                
                # Exponential backoff
                time.sleep((retry_delay / 1000) * (2 ** (attempt - 1)))
        
        raise Exception("Unexpected error in broadcast_with_monitoring")
    
    def wait_for_confirmation(self, tx_id: str, timeout: int = 30000) -> Dict:
        """Wait for transaction confirmation"""
        start_time = time.time() * 1000
        check_interval = 3000  # Check every 3 seconds
        
        while (time.time() * 1000) - start_time < timeout:
            try:
                tx_info = self.get_transaction_info(tx_id)
                
                if tx_info and tx_info.get('blockNumber'):
                    return {
                        'confirmed': True,
                        'block_number': tx_info['blockNumber'],
                        'confirmation_time': (time.time() * 1000) - start_time,
                        'fee': tx_info.get('fee', 0)
                    }
            except Exception as e:
                print(f"Checking confirmation... {str(e)}")
            
            time.sleep(check_interval / 1000)
        
        return {
            'confirmed': False,
            'timeout': True,
            'message': 'Transaction confirmation timeout'
        }
    
    def get_transaction_info(self, tx_id: str) -> Dict:
        """Get transaction information for confirmation"""
        url = f"{self.base_url}/wallet/gettransactionbyid"
        
        payload = {
            'value': tx_id,
            'visible': True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def broadcast_batch(self, signed_transactions: List[Dict], 
                       concurrency: int = 5,
                       delay_between: float = 0.1) -> Dict:
        """Broadcast multiple transactions in batch"""
        results = []
        
        # Process in chunks to respect rate limits
        for i in range(0, len(signed_transactions), concurrency):
            chunk = signed_transactions[i:i + concurrency]
            
            chunk_results = []
            for index, tx in enumerate(chunk):
                try:
                    # Stagger requests slightly
                    time.sleep(index * delay_between)
                    
                    result = self.broadcast_with_monitoring(tx)
                    chunk_results.append({
                        'success': True,
                        'tx_id': tx['txID'],
                        'result': result,
                        'index': i + index
                    })
                except Exception as e:
                    chunk_results.append({
                        'success': False,
                        'tx_id': tx['txID'],
                        'error': str(e),
                        'index': i + index
                    })
            
            results.extend(chunk_results)
            
            # Delay between chunks
            if i + concurrency < len(signed_transactions):
                time.sleep(delay_between * concurrency)
        
        successful = [r for r in results if r['success']]
        failed = [r for r in results if not r['success']]
        
        return {
            'total': len(signed_transactions),
            'successful': len(successful),
            'failed': len(failed),
            'results': results
        }
    
    async def broadcast_async(self, signed_transactions: List[Dict], 
                             concurrency: int = 5) -> Dict:
        """Asynchronous batch broadcasting"""
        semaphore = asyncio.Semaphore(concurrency)
        
        async def broadcast_single(session, tx, index):
            async with semaphore:
                try:
                    async with session.post(
                        f"{self.base_url}/wallet/broadcasttransaction",
                        headers=self.headers,
                        json=tx
                    ) as response:
                        result = await response.json()
                        return {
                            'success': True,
                            'tx_id': tx['txID'],
                            'result': result,
                            'index': index
                        }
                except Exception as e:
                    return {
                        'success': False,
                        'tx_id': tx['txID'],
                        'error': str(e),
                        'index': index
                    }
        
        async with aiohttp.ClientSession() as session:
            tasks = [
                broadcast_single(session, tx, i) 
                for i, tx in enumerate(signed_transactions)
            ]
            results = await asyncio.gather(*tasks, return_exceptions=True)
        
        successful = [r for r in results if isinstance(r, dict) and r.get('success')]
        failed = [r for r in results if isinstance(r, dict) and not r.get('success')]
        
        return {
            'total': len(signed_transactions),
            'successful': len(successful),
            'failed': len(failed),
            'results': results
        }

# Usage examples
if __name__ == "__main__":
    broadcaster = TronBroadcaster('YOUR_API_KEY')
    
    # Example signed transaction
    signed_tx = {
        "txID": "94eea63bb6774c8fc4f4c9d1b62c1e8c2f7c8c2e4d3a2b1c0d9e8f7a6b5c4d3e2f1",
        "raw_data": {
            # ... transaction data
        },
        "signature": ["c8f8f8e8d8c8b8a898887878686858484838281807060504030201"]
    }
    
    try:
        # Single transaction broadcast
        result = broadcaster.broadcast_with_monitoring(
            signed_tx,
            wait_for_confirmation=True,
            max_retries=3
        )
        print(f"Broadcast result: {result}")
        
        # Batch broadcasting
        signed_transactions = [signed_tx]  # List of signed transactions
        
        batch_result = broadcaster.broadcast_batch(
            signed_transactions,
            concurrency=3,
            delay_between=0.2
        )
        print(f"Batch complete: {batch_result['successful']}/{batch_result['total']} successful")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful Broadcast

```json
{
  "result": true,
  "txid": "94eea63bb6774c8fc4f4c9d1b62c1e8c2f7c8c2e4d3a2b1c0d9e8f7a6b5c4d3e2f1"
}
```

### Failed Broadcast (Insufficient Energy)

```json
{
  "result": false,
  "code": "CONTRACT_VALIDATE_ERROR",
  "message": "account does not have enough energy"
}
```

### Network Error

```json
{
  "result": false,
  "code": "SERVER_BUSY",
  "message": "Server is busy, please try again later"
}
```

## Common Use Cases

### 1. Payment Gateway Completion

```javascript
class PaymentProcessor {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.broadcaster = new TronBroadcaster(apiKey);
  }
  
  async processPayment(paymentRequest) {
    try {
      const { signedTransaction, paymentId, amount, customer } = paymentRequest;
      
      console.log(`Processing payment ${paymentId} for ${amount} TRX`);
      
      // Broadcast with monitoring
      const result = await this.broadcaster.broadcast_with_monitoring(
        signedTransaction,
        {
          maxRetries: 5,
          waitForConfirmation: true,
          confirmationTimeout: 60000
        }
      );
      
      if (result.result && result.confirmation?.confirmed) {
        // Payment successful
        await this.updatePaymentStatus(paymentId, 'completed', result.txid);
        await this.notifyCustomer(customer, 'payment_success', result.txid);
        
        return {
          status: 'completed',
          txId: result.txid,
          blockNumber: result.confirmation.blockNumber,
          fee: result.confirmation.fee
        };
      } else {
        throw new Error('Payment confirmation failed');
      }
      
    } catch (error) {
      await this.updatePaymentStatus(paymentId, 'failed', null, error.message);
      await this.notifyCustomer(customer, 'payment_failed', error.message);
      throw error;
    }
  }
  
  async updatePaymentStatus(paymentId, status, txId = null, error = null) {
    // Update payment in database
    console.log(`Payment ${paymentId} status: ${status}`);
  }
  
  async notifyCustomer(customer, event, data) {
    // Send notification to customer
    console.log(`Notifying ${customer}: ${event} - ${data}`);
  }
}
```

### 2. Multi-Signature Transaction Execution

```javascript
async function executeMultiSigTransaction(multiSigTransaction, requiredSignatures) {
  try {
    // Verify we have enough signatures
    if (multiSigTransaction.signature.length < requiredSignatures) {
      throw new Error(`Insufficient signatures: ${multiSigTransaction.signature.length}/${requiredSignatures}`);
    }
    
    console.log(`Executing multi-sig transaction with ${multiSigTransaction.signature.length} signatures`);
    
    const result = await broadcastWithMonitoring(multiSigTransaction, {
      maxRetries: 3,
      waitForConfirmation: true
    });
    
    return {
      executed: true,
      txId: result.txid,
      signatures: multiSigTransaction.signature.length,
      confirmation: result.confirmation
    };
    
  } catch (error) {
    console.error('Multi-sig execution failed:', error);
    return {
      executed: false,
      error: error.message,
      signatures: multiSigTransaction.signature?.length || 0
    };
  }
}
```

### 3. Automated Trading Bot

```javascript
class TronTradingBot {
  constructor(apiKey, strategy) {
    this.apiKey = apiKey;
    this.strategy = strategy;
    this.broadcaster = new TronBroadcaster(apiKey);
    this.pendingTrades = new Map();
  }
  
  async executeTrade(tradeSignal) {
    try {
      const { action, amount, price, signedTransaction } = tradeSignal;
      
      console.log(`Executing ${action} trade: ${amount} TRX at ${price}`);
      
      // Broadcast trade transaction
      const result = await this.broadcaster.broadcast_with_monitoring(
        signedTransaction,
        { 
          maxRetries: 2,
          waitForConfirmation: false // Don't wait for DEX trades
        }
      );
      
      if (result.result) {
        // Track pending trade
        this.pendingTrades.set(result.txid, {
          action,
          amount,
          price,
          timestamp: Date.now(),
          status: 'pending'
        });
        
        // Monitor in background
        this.monitorTradeConfirmation(result.txid);
        
        return {
          success: true,
          tradeId: result.txid,
          action,
          amount,
          price
        };
      } else {
        throw new Error(`Trade broadcast failed: ${result.message}`);
      }
      
    } catch (error) {
      console.error('Trade execution failed:', error);
      return {
        success: false,
        error: error.message,
        action: tradeSignal.action
      };
    }
  }
  
  async monitorTradeConfirmation(txId) {
    // Background monitoring
    setTimeout(async () => {
      try {
        const confirmation = await this.broadcaster.wait_for_confirmation(txId, 30000);
        const trade = this.pendingTrades.get(txId);
        
        if (confirmation.confirmed && trade) {
          trade.status = 'confirmed';
          trade.blockNumber = confirmation.blockNumber;
          console.log(`Trade ${txId} confirmed in block ${confirmation.blockNumber}`);
          
          // Update strategy
          this.strategy.onTradeConfirmed(trade);
        }
      } catch (error) {
        console.error(`Trade monitoring failed for ${txId}:`, error);
      }
    }, 1000);
  }
}
```

### 4. Subscription Payment Processing

```javascript
class SubscriptionManager {
  constructor(apiKey) {
    this.broadcaster = new TronBroadcaster(apiKey);
    this.subscriptions = new Map();
  }
  
  async processSubscriptionPayment(subscriptionId, signedTransaction) {
    try {
      const subscription = this.subscriptions.get(subscriptionId);
      if (!subscription) {
        throw new Error('Subscription not found');
      }
      
      console.log(`Processing subscription payment for ${subscriptionId}`);
      
      const result = await this.broadcaster.broadcast_with_monitoring(
        signedTransaction,
        {
          maxRetries: 3,
          waitForConfirmation: true,
          confirmationTimeout: 45000
        }
      );
      
      if (result.result && result.confirmation?.confirmed) {
        // Update subscription status
        subscription.status = 'active';
        subscription.lastPayment = Date.now();
        subscription.nextBilling = Date.now() + (30 * 24 * 60 * 60 * 1000); // 30 days
        subscription.txId = result.txid;
        
        await this.activateSubscription(subscriptionId);
        await this.scheduleNextBilling(subscriptionId);
        
        return {
          success: true,
          subscriptionId,
          txId: result.txid,
          nextBilling: subscription.nextBilling
        };
      } else {
        throw new Error('Payment confirmation failed');
      }
      
    } catch (error) {
      console.error(`Subscription payment failed for ${subscriptionId}:`, error);
      
      // Update subscription status
      const subscription = this.subscriptions.get(subscriptionId);
      if (subscription) {
        subscription.status = 'payment_failed';
        subscription.lastError = error.message;
      }
      
      throw error;
    }
  }
  
  async activateSubscription(subscriptionId) {
    console.log(`Activating subscription ${subscriptionId}`);
    // Activate user's subscription features
  }
  
  async scheduleNextBilling(subscriptionId) {
    const subscription = this.subscriptions.get(subscriptionId);
    if (subscription) {
      console.log(`Next billing for ${subscriptionId}: ${new Date(subscription.nextBilling)}`);
      // Schedule next payment reminder
    }
  }
}
```

## Performance Tips

1. **Parallel Processing** - Broadcast multiple transactions concurrently with rate limiting
2. **Retry Strategy** - Implement exponential backoff for failed broadcasts
3. **Confirmation Polling** - Use efficient polling intervals for transaction confirmation
4. **Error Recovery** - Handle different error types with appropriate recovery strategies

```javascript
// Performance-optimized batch broadcaster
class OptimizedBroadcaster {
  constructor(apiKey, options = {}) {
    this.apiKey = apiKey;
    this.maxConcurrency = options.maxConcurrency || 10;
    this.rateLimitPerSecond = options.rateLimitPerSecond || 20;
    this.queue = [];
    this.processing = false;
  }
  
  async addToBroadcastQueue(signedTransaction, priority = 'normal') {
    return new Promise((resolve, reject) => {
      this.queue.push({
        transaction: signedTransaction,
        priority,
        resolve,
        reject,
        timestamp: Date.now()
      });
      
      this.processQueue();
    });
  }
  
  async processQueue() {
    if (this.processing) return;
    this.processing = true;
    
    // Sort by priority
    this.queue.sort((a, b) => {
      const priorities = { high: 3, normal: 2, low: 1 };
      return priorities[b.priority] - priorities[a.priority];
    });
    
    while (this.queue.length > 0) {
      const batch = this.queue.splice(0, this.maxConcurrency);
      
      const promises = batch.map(async (item, index) => {
        // Stagger requests to respect rate limits
        await new Promise(resolve => 
          setTimeout(resolve, (index * 1000) / this.rateLimitPerSecond)
        );
        
        try {
          const result = await broadcastWithMonitoring(item.transaction);
          item.resolve(result);
        } catch (error) {
          item.reject(error);
        }
      });
      
      await Promise.allSettled(promises);
    }
    
    this.processing = false;
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/createtransaction - Create TRON Transact...

# wallet/createtransaction - Create TRON Transact...

**Dwellir's TRON endpoints** create transactions in under 30ms with automatic fee optimization.
Build instant payment apps with our optimized transaction creation API.

[Get your free API key](https://dashboard.dwellir.com/register)

Creates a TRX transfer transaction that can be signed and broadcast to the TRON network. This method generates the transaction object with all necessary parameters.

## When to Use This Method

`wallet/createtransaction` is essential for:

- **TRX Transfers** - Send TRX between accounts
- **Payment Processing** - Build payment systems and wallets
- **Batch Transactions** - Create multiple transfers efficiently
- **Multi-Signature Wallets** - Generate transactions for signing
- **Transaction Templates** - Pre-build transactions for later execution

## Request Parameters

- `to_address` (`string, required`): Recipient's TRON address in Base58 format Example: `"TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"`
- `owner_address` (`string, required`): Sender's TRON address in Base58 format Example: `"TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh"`
- `amount` (`integer, required`): Amount to transfer in SUN (1 TRX = 1,000,000 SUN) Example: `1000000` (1 TRX)
- `visible` (`boolean, optional`): `true` - Use Base58 address format `false` - Use hex address format

## Request Example

```json
{
  "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
  "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh", 
  "amount": 1000000,
  "visible": true
}
```

## Response Fields

- `result` (`OBJECT, required`): `txID` - Transaction hash identifier `raw_data` - Transaction data requiring signatures `raw_data_hex` - Hex encoded transaction data `visible` - Address format used in response

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Error Responses

### Error 1

- Code: `CONTRACT_VALIDATE_ERROR`
- Description: Validation failed

### Error 2

- Code: `BANDWIDTH_ERROR`
- Description: Insufficient bandwidth

### Error 3

- Code: `INVALID_ADDRESS`
- Description: Malformed address

### Error 4

- Code: `AMOUNT_TOO_SMALL`
- Description: Amount below minimum

## Implementation Examples

cURL
JavaScript
Python

```bash
# Create a basic TRX transfer transaction
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/createtransaction" \
  -H "Content-Type: application/json" \
  -d '{
    "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
    "amount": 1000000,
    "visible": true
  }'

# Create transaction with hex addresses
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/createtransaction" \
  -H "Content-Type: application/json" \
  -d '{
    "to_address": "41E552F6487585C2B58BC2C9BB4492BC1F17132CD0",
    "owner_address": "41928C9AF0651632157EF27A2F8B31B343C9E859",
    "amount": 1000000,
    "visible": false
  }'

# Extract transaction ID from response
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/createtransaction" \
  -H "Content-Type: application/json" \
  -d '{
    "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
    "amount": 2500000,
    "visible": true
  }' | jq '{
    txID: .txID,
    amount_trx: (.raw_data.contract[0].parameter.value.amount // 0) / 1000000,
    from: .raw_data.contract[0].parameter.value.owner_address,
    to: .raw_data.contract[0].parameter.value.to_address,
    expiration: .raw_data.expiration
  }'

# Batch script for multiple transactions
#!/bin/bash
API_KEY="YOUR_API_KEY"
FROM_ADDRESS="TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh"

declare -a recipients=(
  "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN:1000000"
  "TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy:2000000"
  "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9:500000"
)

for recipient in "${recipients[@]}"; do
  IFS=':' read -ra ADDR <<< "$recipient"
  TO_ADDRESS="${ADDR[0]}"
  AMOUNT="${ADDR[1]}"
  
  echo "Creating transaction to $TO_ADDRESS for $AMOUNT SUN..."
  
  curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/createtransaction" \
    -H "Content-Type: application/json" \
    -d "{
      \"to_address\": \"$TO_ADDRESS\",
      \"owner_address\": \"$FROM_ADDRESS\",
      \"amount\": $AMOUNT,
      \"visible\": true
    }" | jq '.txID'
  
  sleep 1  # Rate limiting
done
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Create a simple TRX transfer transaction
async function createTransaction(fromAddress, toAddress, amount) {
  const response = await fetch(`${TRON_API}/wallet/createtransaction`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      to_address: toAddress,
      owner_address: fromAddress,
      amount: amount, // Amount in SUN
      visible: true
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Enhanced transaction creation with validation
async function createTRXTransfer(fromAddress, toAddress, amountTRX) {
  try {
    // Validate addresses
    if (!isValidTronAddress(fromAddress) || !isValidTronAddress(toAddress)) {
      throw new Error('Invalid TRON address format');
    }

    // Convert TRX to SUN
    const amountSUN = Math.floor(amountTRX * 1_000_000);
    
    if (amountSUN <= 0) {
      throw new Error('Amount must be greater than 0');
    }

    // Create transaction
    const transaction = await createTransaction(fromAddress, toAddress, amountSUN);
    
    // Add metadata
    return {
      ...transaction,
      metadata: {
        fromAddress,
        toAddress,
        amountTRX,
        amountSUN,
        createdAt: Date.now(),
        expiresAt: Date.now() + (60 * 60 * 1000) // 1 hour
      }
    };
  } catch (error) {
    console.error('Error creating transaction:', error);
    throw error;
  }
}

// Batch transaction creation
async function createBatchTransactions(fromAddress, transfers) {
  const transactions = [];
  
  for (const transfer of transfers) {
    try {
      const tx = await createTRXTransfer(
        fromAddress, 
        transfer.toAddress, 
        transfer.amount
      );
      transactions.push({
        success: true,
        transaction: tx,
        recipient: transfer.toAddress,
        amount: transfer.amount
      });
    } catch (error) {
      transactions.push({
        success: false,
        error: error.message,
        recipient: transfer.toAddress,
        amount: transfer.amount
      });
    }
  }
  
  return transactions;
}

// Transaction with memo (using smart contract)
async function createTransactionWithMemo(fromAddress, toAddress, amount, memo) {
  // For simple transfers with memo, you'd typically use a smart contract
  // This example shows the basic transaction creation
  const transaction = await createTransaction(fromAddress, toAddress, amount);
  
  // Add memo to transaction metadata (not on-chain for basic transfers)
  transaction.memo = memo;
  return transaction;
}

// Utility function to validate TRON addresses
function isValidTronAddress(address) {
  // Basic validation - starts with T and is 34 characters
  return typeof address === 'string' && 
         address.startsWith('T') && 
         address.length === 34;
}

// Usage examples
(async () => {
  try {
    // Single transaction
    const tx = await createTRXTransfer(
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
      1.5 // 1.5 TRX
    );
    console.log('Transaction created:', tx.txID);
    
    // Batch transactions
    const transfers = [
      { toAddress: 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', amount: 1 },
      { toAddress: 'TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy', amount: 2 },
      { toAddress: 'TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9', amount: 0.5 }
    ];
    
    const batchTxs = await createBatchTransactions(
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
      transfers
    );
    console.log('Batch transactions:', batchTxs);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import time
from typing import Dict, List, Optional

class TronTransactionBuilder:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def create_transaction(self, from_address: str, to_address: str, amount_sun: int) -> Dict:
        """Create a TRX transfer transaction"""
        url = f"{self.base_url}/wallet/createtransaction"
        
        payload = {
            "to_address": to_address,
            "owner_address": from_address,
            "amount": amount_sun,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def create_trx_transfer(self, from_address: str, to_address: str, amount_trx: float) -> Dict:
        """Create TRX transfer with validation and metadata"""
        # Validate addresses
        if not self._is_valid_tron_address(from_address) or not self._is_valid_tron_address(to_address):
            raise ValueError("Invalid TRON address format")
        
        # Convert TRX to SUN
        amount_sun = int(amount_trx * 1_000_000)
        
        if amount_sun <= 0:
            raise ValueError("Amount must be greater than 0")
        
        # Create transaction
        transaction = self.create_transaction(from_address, to_address, amount_sun)
        
        # Add metadata
        transaction['metadata'] = {
            'from_address': from_address,
            'to_address': to_address,
            'amount_trx': amount_trx,
            'amount_sun': amount_sun,
            'created_at': int(time.time() * 1000),
            'expires_at': int((time.time() + 3600) * 1000)  # 1 hour
        }
        
        return transaction
    
    def create_batch_transactions(self, from_address: str, transfers: List[Dict]) -> List[Dict]:
        """Create multiple transactions in batch"""
        transactions = []
        
        for transfer in transfers:
            try:
                tx = self.create_trx_transfer(
                    from_address,
                    transfer['to_address'],
                    transfer['amount']
                )
                transactions.append({
                    'success': True,
                    'transaction': tx,
                    'recipient': transfer['to_address'],
                    'amount': transfer['amount']
                })
            except Exception as e:
                transactions.append({
                    'success': False,
                    'error': str(e),
                    'recipient': transfer['to_address'],
                    'amount': transfer['amount']
                })
        
        return transactions
    
    def estimate_transaction_cost(self, from_address: str, to_address: str, amount_sun: int) -> Dict:
        """Estimate bandwidth cost for transaction"""
        try:
            # Create transaction to get size
            tx = self.create_transaction(from_address, to_address, amount_sun)
            
            # Estimate bandwidth usage (basic calculation)
            tx_size = len(json.dumps(tx['raw_data']).encode('utf-8'))
            bandwidth_cost = tx_size  # Approximate bandwidth points needed
            
            return {
                'transaction_size': tx_size,
                'bandwidth_cost': bandwidth_cost,
                'will_use_free_bandwidth': bandwidth_cost <= 5000,  # Assuming 5000 free bandwidth
                'estimated_fee_trx': 0 if bandwidth_cost <= 5000 else (bandwidth_cost * 0.001) / 1_000_000
            }
        except Exception as e:
            return {'error': str(e)}
    
    def _is_valid_tron_address(self, address: str) -> bool:
        """Validate TRON address format"""
        return (isinstance(address, str) and 
                address.startswith('T') and 
                len(address) == 34)

# Usage examples
if __name__ == "__main__":
    builder = TronTransactionBuilder('YOUR_API_KEY')
    
    try:
        # Single transaction
        tx = builder.create_trx_transfer(
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            1.5  # 1.5 TRX
        )
        print(f"Transaction created: {tx['txID']}")
        
        # Estimate cost
        cost = builder.estimate_transaction_cost(
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            1_500_000
        )
        print(f"Transaction cost: {cost}")
        
        # Batch transactions
        transfers = [
            {'to_address': 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 'amount': 1},
            {'to_address': 'TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy', 'amount': 2},
            {'to_address': 'TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9', 'amount': 0.5}
        ]
        
        batch_txs = builder.create_batch_transactions(
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
            transfers
        )
        
        successful_txs = [tx for tx in batch_txs if tx['success']]
        print(f"Successfully created {len(successful_txs)} transactions")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful Transaction Creation

```json
{
  "visible": true,
  "txID": "94eea63bb6774c8fc4f4c9d1b62c1e8c2f7c8c2e4d3a2b1c0d9e8f7a6b5c4d3e2f1",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "amount": 1000000,
            "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
            "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
          },
          "type_url": "type.googleapis.com/protocol.TransferContract"
        },
        "type": "TransferContract"
      }
    ],
    "ref_block_bytes": "4a7b",
    "ref_block_hash": "e15e44aa73bd9e15",
    "expiration": 1734567890000,
    "timestamp": 1734567830000
  },
  "raw_data_hex": "0a024a7b2208e15e44aa73bd9e1540d0c7e7e7e7e32d5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a15418e9e8b7a4b5c6d3e2f1a0b9c8d7e6f5a4b3c2d1e0f12154142b5e01c8c59a25d78acdbec2bfc7e89e5e86318c0843d70a0b7c6d5e4f3a2b1c0"
}
```

### Error Response (Insufficient Balance)

```json
{
  "Error": "balance is not sufficient",
  "code": "CONTRACT_VALIDATE_ERROR"
}
```

## Common Use Cases

### 1. Payment Gateway Integration

```javascript
class TronPaymentGateway {
  constructor(apiKey, merchantAddress) {
    this.apiKey = apiKey;
    this.merchantAddress = merchantAddress;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }
  
  async createPayment(customerAddress, amountUSD, usdToTrxRate) {
    const amountTRX = amountUSD / usdToTrxRate;
    const amountSUN = Math.floor(amountTRX * 1_000_000);
    
    const transaction = await this.createTransaction(
      customerAddress,
      this.merchantAddress,
      amountSUN
    );
    
    return {
      paymentId: transaction.txID,
      amountTRX: amountTRX,
      amountUSD: amountUSD,
      transaction: transaction,
      expiresAt: Date.now() + (15 * 60 * 1000) // 15 minutes
    };
  }
  
  async createTransaction(from, to, amount) {
    const response = await fetch(`${this.apiUrl}/wallet/createtransaction`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        to_address: to,
        owner_address: from,
        amount: amount,
        visible: true
      })
    });
    
    return await response.json();
  }
}
```

### 2. Wallet-to-Wallet Transfer

```javascript
async function createWalletTransfer(fromWallet, toWallet, amount, memo = '') {
  try {
    // Validate inputs
    if (!isValidTronAddress(fromWallet) || !isValidTronAddress(toWallet)) {
      throw new Error('Invalid wallet address');
    }
    
    if (amount <= 0) {
      throw new Error('Amount must be positive');
    }
    
    // Check sender balance first
    const senderAccount = await fetch(`${TRON_API}/wallet/getaccount`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ address: fromWallet, visible: true })
    }).then(res => res.json());
    
    const balanceTRX = (senderAccount.balance || 0) / 1_000_000;
    
    if (balanceTRX < amount) {
      throw new Error(`Insufficient balance. Have: ${balanceTRX} TRX, Need: ${amount} TRX`);
    }
    
    // Create transaction
    const transaction = await createTRXTransfer(fromWallet, toWallet, amount);
    
    return {
      transaction,
      summary: {
        from: fromWallet,
        to: toWallet,
        amount: amount,
        fee: 'Free (using bandwidth)',
        memo: memo,
        requiresSigning: true
      }
    };
  } catch (error) {
    throw new Error(`Transfer creation failed: ${error.message}`);
  }
}
```

### 3. Subscription Payment System

```javascript
class TronSubscriptionManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.subscriptions = new Map();
  }
  
  async createSubscriptionPayment(subscriberAddress, planPrice, planId) {
    const subscriptionId = `sub_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    
    const transaction = await createTRXTransfer(
      subscriberAddress,
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh', // Merchant address
      planPrice
    );
    
    this.subscriptions.set(subscriptionId, {
      id: subscriptionId,
      planId: planId,
      subscriberAddress: subscriberAddress,
      amount: planPrice,
      transaction: transaction,
      status: 'pending',
      createdAt: Date.now()
    });
    
    return {
      subscriptionId,
      transaction,
      expiresAt: Date.now() + (30 * 60 * 1000) // 30 minutes to pay
    };
  }
  
  getSubscription(subscriptionId) {
    return this.subscriptions.get(subscriptionId);
  }
}
```

### 4. Multi-Recipient Airdrop

```javascript
async function createAirdropTransactions(distributorAddress, recipients, amountPerRecipient) {
  const results = {
    successful: [],
    failed: [],
    totalRecipients: recipients.length,
    totalAmount: recipients.length * amountPerRecipient
  };
  
  console.log(`Creating airdrop for ${recipients.length} recipients...`);
  
  for (let i = 0; i < recipients.length; i++) {
    const recipient = recipients[i];
    
    try {
      const transaction = await createTRXTransfer(
        distributorAddress,
        recipient,
        amountPerRecipient
      );
      
      results.successful.push({
        recipient: recipient,
        transaction: transaction,
        amount: amountPerRecipient
      });
      
      console.log(`✓ Created transaction ${i + 1}/${recipients.length} for ${recipient}`);
      
    } catch (error) {
      results.failed.push({
        recipient: recipient,
        error: error.message,
        amount: amountPerRecipient
      });
      
      console.log(`✗ Failed transaction ${i + 1}/${recipients.length} for ${recipient}: ${error.message}`);
    }
    
    // Rate limiting - wait 100ms between requests
    if (i < recipients.length - 1) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }
  
  return results;
}
```

## Performance Tips

1. **Batch Creation** - Create multiple transactions concurrently but respect rate limits
2. **Pre-validation** - Check balances and addresses before creating transactions
3. **Caching** - Cache account data to avoid repeated balance checks
4. **Error Recovery** - Implement retry logic for transient failures

```javascript
// Rate limited transaction creation
class RateLimitedTransactionBuilder {
  constructor(apiKey, requestsPerSecond = 10) {
    this.apiKey = apiKey;
    this.requestQueue = [];
    this.isProcessing = false;
    this.requestsPerSecond = requestsPerSecond;
  }
  
  async createTransaction(fromAddress, toAddress, amount) {
    return new Promise((resolve, reject) => {
      this.requestQueue.push({ fromAddress, toAddress, amount, resolve, reject });
      this.processQueue();
    });
  }
  
  async processQueue() {
    if (this.isProcessing || this.requestQueue.length === 0) return;
    
    this.isProcessing = true;
    
    while (this.requestQueue.length > 0) {
      const request = this.requestQueue.shift();
      
      try {
        const result = await createTRXTransfer(
          request.fromAddress,
          request.toAddress,
          request.amount
        );
        request.resolve(result);
      } catch (error) {
        request.reject(error);
      }
      
      // Rate limiting delay
      await new Promise(resolve => setTimeout(resolve, 1000 / this.requestsPerSecond));
    }
    
    this.isProcessing = false;
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/delegateresource - Delegate TRX Resources

# wallet/delegateresource - Delegate TRX Resources

Delegate staked bandwidth or energy resources to another TRON account.

## Endpoint

```
POST /wallet/delegateresource
```

## Request Parameters

- `owner_address` (`string, required`): Required parameter: Account address delegating resources (base58)
- `receiver_address` (`string, required`): Required parameter: Account receiving delegated resources (base58)
- `balance` (`number, required`): Required parameter: Amount to delegate in SUN (1 TRX = 1,000,000 SUN)
- `resource` (`string, required`): Required parameter: Resource type: "BANDWIDTH" or "ENERGY"
- `lock` (`boolean, required`): Optional parameter: Lock delegation for 3 days (default: false)
- `lock_period` (`number, required`): Optional parameter: Custom lock period in seconds (if lock=true)
- `permission_id` (`number, required`): Optional parameter: Permission ID for multi-signature (default: 0)
- `visible` (`boolean, required`): Optional parameter: Return base58 addresses (default: false returns hex)

## Request Example

```bash
# Basic energy delegation
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/delegateresource \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TOwnerAddress...",
        "receiver_address": "TReceiverAddress...",
        "balance": 1000000000,
        "resource": "ENERGY",
        "visible": true
      }'

    # Delegate bandwidth with 3-day lock
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/delegateresource \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TOwnerAddress...",
        "receiver_address": "TReceiverAddress...",
        "balance": 500000000,
        "resource": "BANDWIDTH",
        "lock": true,
        "lock_period": 259200,
        "visible": true
      }'

    # Check delegation index
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresourceaccountindex \
      -H "Content-Type: application/json" \
      -d '{
        "value": "TOwnerAddress...",
        "visible": true
      }'

    # Get delegation details between accounts
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresource \
      -H "Content-Type: application/json" \
      -d '{
        "fromAddress": "TOwnerAddress...",
        "toAddress": "TReceiverAddress...",
        "visible": true
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `txID` - Transaction hash `raw_data` - Transaction raw data `contract` - Delegation contract details `expiration` - Transaction expiration timestamp `timestamp` - Transaction creation timestamp `visible` - Address format indicator

## Successful Response

```json
{
  "visible": true,
  "txID": "d8f3c4b9e2a7d6c5e4f3b2a1d9c8e7f6b5a4d3c2e1f9a8b7c6d5e4f3a2b1c9e",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "owner_address": "TOwnerAddress...",
            "receiver_address": "TReceiverAddress...",
            "balance": 1000000000,
            "resource": "ENERGY",
            "lock": true,
            "lock_period": 259200
          },
          "type_url": "type.googleapis.com/protocol.DelegateResourceContract"
        },
        "type": "DelegateResourceContract"
      }
    ],
    "ref_block_bytes": "6b5c",
    "ref_block_hash": "4d3e5f9a8b7c6d5e",
    "expiration": 1702456849000,
    "timestamp": 1702456789000
  }
}
```

## Important Notes

### Delegation Rules

1. **Must Stake First**: Resources must be staked before delegation
2. **Immediate Effect**: Delegation takes effect immediately after transaction confirmation
3. **Lock Period**: Optional 3-day lock prevents immediate reclaim
4. **Resource Ownership**: Delegated resources remain owned by delegator
5. **Reclaim Process**: Use `undelegateresource` to reclaim delegated resources

### Resource Calculations

- Energy delegation helps with smart contract execution
- Bandwidth delegation helps with transactions and transfers
- Receiver pays no TRX but can use delegated resources

## Implementation Examples

cURL
JavaScript
Python

```bash
# Basic energy delegation
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/delegateresource \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TOwnerAddress...",
    "receiver_address": "TReceiverAddress...",
    "balance": 1000000000,
    "resource": "ENERGY",
    "visible": true
  }'

# Delegate bandwidth with 3-day lock
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/delegateresource \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TOwnerAddress...",
    "receiver_address": "TReceiverAddress...",
    "balance": 500000000,
    "resource": "BANDWIDTH",
    "lock": true,
    "lock_period": 259200,
    "visible": true
  }'

# Check delegation index
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresourceaccountindex \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TOwnerAddress...",
    "visible": true
  }'

# Get delegation details between accounts
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresource \
  -H "Content-Type: application/json" \
  -d '{
    "fromAddress": "TOwnerAddress...",
    "toAddress": "TReceiverAddress...",
    "visible": true
  }'
```

```javascript
class TronDelegationManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }

  // Create delegation transaction
  async delegateResources(ownerAddress, receiverAddress, amountTRX, resourceType, lock = false) {
    const response = await fetch(`${this.baseUrl}/wallet/delegateresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        owner_address: ownerAddress,
        receiver_address: receiverAddress,
        balance: amountTRX * 1000000, // Convert TRX to SUN
        resource: resourceType,
        lock: lock,
        lock_period: lock ? 3 * 24 * 3600 : undefined, // 3 days in seconds
        visible: true
      })
    });

    if (!response.ok) {
      throw new Error(`Delegation failed: ${response.statusText}`);
    }

    return response.json();
  }

  // Check delegated resources for an account
  async getDelegatedResources(address) {
    const response = await fetch(`${this.baseUrl}/wallet/getdelegatedresourceaccountindex`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        value: address,
        visible: true
      })
    });

    const data = await response.json();
    
    // Get detailed info for each delegation
    const delegations = [];
    
    if (data.toAccounts) {
      for (const account of data.toAccounts) {
        const detail = await this.getDelegationDetail(address, account);
        delegations.push(detail);
      }
    }
    
    return delegations;
  }

  // Get detailed delegation info between two accounts
  async getDelegationDetail(from, to) {
    const response = await fetch(`${this.baseUrl}/wallet/getdelegatedresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        fromAddress: from,
        toAddress: to,
        visible: true
      })
    });

    return response.json();
  }

  // Calculate optimal delegation based on receiver's needs
  async calculateOptimalDelegation(receiverAddress, contractAddress = null) {
    // Get receiver's current resources
    const resourceResponse = await fetch(`${this.baseUrl}/wallet/getaccountresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        address: receiverAddress,
        visible: true
      })
    });

    const resources = await resourceResponse.json();
    
    // Estimate energy needs if contract address provided
    let energyNeeded = 0;
    if (contractAddress) {
      const contractResponse = await fetch(`${this.baseUrl}/wallet/triggerconstantcontract`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          owner_address: receiverAddress,
          contract_address: contractAddress,
          function_selector: 'estimateEnergy()',
          visible: true
        })
      });
      
      const contractData = await contractResponse.json();
      energyNeeded = contractData.energy_used || 50000; // Default 50k energy
    }
    
    // Calculate delegation amounts
    const currentEnergy = resources.EnergyLimit || 0;
    const currentBandwidth = resources.NetLimit || 0;
    const freeNetUsed = resources.freeNetUsed || 0;
    
    return {
      energy: {
        current: currentEnergy,
        needed: energyNeeded,
        delegate: Math.max(0, energyNeeded - currentEnergy),
        delegateTRX: Math.ceil((energyNeeded - currentEnergy) / 28.5) // Approximate ratio
      },
      bandwidth: {
        current: currentBandwidth,
        dailyUsage: freeNetUsed,
        delegate: Math.max(0, 5000 - currentBandwidth), // Aim for 5000 bandwidth
        delegateTRX: Math.max(0, 5000 - currentBandwidth) // 1 TRX = 1 bandwidth
      }
    };
  }

  // Batch delegate to multiple receivers
  async batchDelegate(ownerAddress, delegations) {
    const transactions = [];
    
    for (const delegation of delegations) {
      const tx = await this.delegateResources(
        ownerAddress,
        delegation.receiver,
        delegation.amount,
        delegation.resource,
        delegation.lock || false
      );
      
      transactions.push({
        receiver: delegation.receiver,
        resource: delegation.resource,
        amount: delegation.amount,
        txID: tx.txID,
        transaction: tx
      });
    }
    
    return transactions;
  }
}

// Advanced delegation strategies
class DelegationStrategy {
  constructor(manager) {
    this.manager = manager;
  }

  // Delegate to DApp users based on usage patterns
  async delegateForDApp(ownerAddress, dappUsers) {
    const delegations = [];
    
    for (const user of dappUsers) {
      // Calculate needs based on historical usage
      const optimal = await this.manager.calculateOptimalDelegation(
        user.address,
        user.primaryContract
      );
      
      if (optimal.energy.delegate > 0) {
        delegations.push({
          receiver: user.address,
          resource: 'ENERGY',
          amount: optimal.energy.delegateTRX,
          lock: true // Lock for stability
        });
      }
      
      if (optimal.bandwidth.delegate > 0) {
        delegations.push({
          receiver: user.address,
          resource: 'BANDWIDTH',
          amount: optimal.bandwidth.delegateTRX,
          lock: false // Flexible bandwidth
        });
      }
    }
    
    return this.manager.batchDelegate(ownerAddress, delegations);
  }

  // Dynamic delegation based on real-time needs
  async dynamicDelegation(ownerAddress, receiverAddress, threshold = 0.8) {
    const interval = setInterval(async () => {
      try {
        // Check receiver's resource usage
        const resourceResponse = await fetch(
          `${this.manager.baseUrl}/wallet/getaccountresource`,
          {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              address: receiverAddress,
              visible: true
            })
          }
        );
        
        const resources = await resourceResponse.json();
        
        // Check energy usage
        const energyUsage = resources.EnergyUsed / resources.EnergyLimit;
        if (energyUsage > threshold) {
          console.log(`High energy usage detected: ${(energyUsage * 100).toFixed(1)}%`);
          
          // Delegate additional energy
          const additionalEnergy = Math.ceil(resources.EnergyLimit * 0.5);
          const tx = await this.manager.delegateResources(
            ownerAddress,
            receiverAddress,
            additionalEnergy / 28.5, // Convert to TRX
            'ENERGY',
            false
          );
          
          console.log(`Delegated additional energy: TX ${tx.txID}`);
        }
        
        // Check bandwidth usage
        const netUsage = resources.NetUsed / resources.NetLimit;
        if (netUsage > threshold) {
          console.log(`High bandwidth usage detected: ${(netUsage * 100).toFixed(1)}%`);
          
          // Delegate additional bandwidth
          const additionalBandwidth = Math.ceil(resources.NetLimit * 0.5);
          const tx = await this.manager.delegateResources(
            ownerAddress,
            receiverAddress,
            additionalBandwidth,
            'BANDWIDTH',
            false
          );
          
          console.log(`Delegated additional bandwidth: TX ${tx.txID}`);
        }
        
      } catch (error) {
        console.error('Dynamic delegation error:', error);
      }
    }, 60000); // Check every minute
    
    return interval;
  }
}

// Example usage
async function manageDelegation() {
  const manager = new TronDelegationManager('YOUR_API_KEY');
  const strategy = new DelegationStrategy(manager);
  
  try {
    // Simple delegation
    const simpleTx = await manager.delegateResources(
      'TOwnerAddress...',
      'TReceiverAddress...',
      1000, // 1000 TRX
      'ENERGY',
      true // Lock for 3 days
    );
    console.log('Simple delegation TX:', simpleTx.txID);
    
    // Calculate optimal delegation
    const optimal = await manager.calculateOptimalDelegation(
      'TReceiverAddress...',
      'TContractAddress...'
    );
    console.log('Optimal delegation:', optimal);
    
    // Batch delegation to multiple users
    const dappUsers = [
      { address: 'TUser1...', primaryContract: 'TContract1...' },
      { address: 'TUser2...', primaryContract: 'TContract2...' }
    ];
    
    const batchTxs = await strategy.delegateForDApp('TOwnerAddress...', dappUsers);
    console.log('Batch delegations:', batchTxs);
    
    // Start dynamic delegation monitoring
    const monitor = await strategy.dynamicDelegation(
      'TOwnerAddress...',
      'TReceiverAddress...',
      0.75 // Trigger at 75% usage
    );
    
    console.log('Dynamic delegation monitor started');
    
  } catch (error) {
    console.error('Delegation error:', error);
  }
}
```

```python
import requests
import json
import time
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass

@dataclass
class DelegationConfig:
    receiver: str
    amount_trx: float
    resource: str
    lock: bool = False
    lock_period: Optional[int] = None

class TronDelegationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
    
    def delegate_resources(
        self,
        owner_address: str,
        receiver_address: str,
        amount_trx: float,
        resource: str,
        lock: bool = False,
        lock_period: Optional[int] = None
    ) -> Dict:
        """Create a resource delegation transaction"""
        
        payload = {
            "owner_address": owner_address,
            "receiver_address": receiver_address,
            "balance": int(amount_trx * 1_000_000),  # Convert to SUN
            "resource": resource,
            "lock": lock,
            "visible": True
        }
        
        if lock and lock_period:
            payload["lock_period"] = lock_period
        elif lock:
            payload["lock_period"] = 3 * 24 * 3600  # Default 3 days
        
        response = requests.post(
            f"{self.base_url}/wallet/delegateresource",
            json=payload
        )
        response.raise_for_status()
        return response.json()
    
    def get_delegation_index(self, address: str) -> Dict:
        """Get delegation index for an account"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getdelegatedresourceaccountindex",
            json={
                "value": address,
                "visible": True
            }
        )
        response.raise_for_status()
        return response.json()
    
    def get_delegation_detail(
        self,
        from_address: str,
        to_address: str
    ) -> Dict:
        """Get detailed delegation between two accounts"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getdelegatedresource",
            json={
                "fromAddress": from_address,
                "toAddress": to_address,
                "visible": True
            }
        )
        response.raise_for_status()
        return response.json()
    
    def analyze_delegation_needs(
        self,
        receiver_address: str,
        days: int = 1
    ) -> Dict:
        """Analyze resource needs for optimal delegation"""
        
        # Get account resource info
        response = requests.post(
            f"{self.base_url}/wallet/getaccountresource",
            json={
                "address": receiver_address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        resources = response.json()
        
        # Calculate daily needs
        energy_limit = resources.get('EnergyLimit', 0)
        energy_used = resources.get('EnergyUsed', 0)
        net_limit = resources.get('NetLimit', 0)
        net_used = resources.get('NetUsed', 0)
        
        # Estimate required delegation
        energy_deficit = max(0, energy_used * days - energy_limit)
        bandwidth_deficit = max(0, net_used * days - net_limit)
        
        return {
            'energy': {
                'current_limit': energy_limit,
                'daily_usage': energy_used,
                'deficit': energy_deficit,
                'recommended_delegation_trx': energy_deficit / 28.5 if energy_deficit > 0 else 0
            },
            'bandwidth': {
                'current_limit': net_limit,
                'daily_usage': net_used,
                'deficit': bandwidth_deficit,
                'recommended_delegation_trx': bandwidth_deficit if bandwidth_deficit > 0 else 0
            }
        }
    
    def batch_delegate(
        self,
        owner_address: str,
        delegations: List[DelegationConfig]
    ) -> List[Dict]:
        """Execute multiple delegations"""
        
        results = []
        
        for config in delegations:
            try:
                tx = self.delegate_resources(
                    owner_address,
                    config.receiver,
                    config.amount_trx,
                    config.resource,
                    config.lock,
                    config.lock_period
                )
                
                results.append({
                    'success': True,
                    'receiver': config.receiver,
                    'resource': config.resource,
                    'amount_trx': config.amount_trx,
                    'txID': tx['txID'],
                    'transaction': tx
                })
            except Exception as e:
                results.append({
                    'success': False,
                    'receiver': config.receiver,
                    'resource': config.resource,
                    'error': str(e)
                })
        
        return results

class SmartDelegationStrategy:
    """Advanced delegation strategies for different use cases"""
    
    def __init__(self, manager: TronDelegationManager):
        self.manager = manager
    
    def delegate_for_gaming(
        self,
        owner_address: str,
        player_addresses: List[str]
    ) -> List[Dict]:
        """Optimized delegation for gaming DApps"""
        
        delegations = []
        
        for player in player_addresses:
            # Gaming typically needs more energy for contracts
            delegations.append(DelegationConfig(
                receiver=player,
                amount_trx=5000,  # ~142,500 energy
                resource='ENERGY',
                lock=True  # Lock for stable gameplay
            ))
            
            # Moderate bandwidth for transactions
            delegations.append(DelegationConfig(
                receiver=player,
                amount_trx=1000,  # 1000 bandwidth
                resource='BANDWIDTH',
                lock=False
            ))
        
        return self.manager.batch_delegate(owner_address, delegations)
    
    def delegate_for_defi(
        self,
        owner_address: str,
        trader_addresses: List[str]
    ) -> List[Dict]:
        """Optimized delegation for DeFi trading"""
        
        delegations = []
        
        for trader in trader_addresses:
            # DeFi needs high energy for swaps/liquidity
            delegations.append(DelegationConfig(
                receiver=trader,
                amount_trx=10000,  # ~285,000 energy
                resource='ENERGY',
                lock=False  # Flexible for trading
            ))
            
            # High bandwidth for frequent transactions
            delegations.append(DelegationConfig(
                receiver=trader,
                amount_trx=2000,  # 2000 bandwidth
                resource='BANDWIDTH',
                lock=False
            ))
        
        return self.manager.batch_delegate(owner_address, delegations)
    
    def progressive_delegation(
        self,
        owner_address: str,
        receiver_address: str,
        initial_amount: float,
        increment: float,
        max_amount: float
    ) -> None:
        """Progressive delegation based on usage"""
        
        current_delegation = initial_amount
        
        while current_delegation <= max_amount:
            # Check current usage
            analysis = self.manager.analyze_delegation_needs(receiver_address)
            
            # Delegate if needed
            if analysis['energy']['deficit'] > 0:
                tx = self.manager.delegate_resources(
                    owner_address,
                    receiver_address,
                    current_delegation,
                    'ENERGY',
                    lock=False
                )
                print(f"Delegated {current_delegation} TRX for energy: {tx['txID']}")
                
                # Increase for next iteration
                current_delegation += increment
                
                # Wait before checking again
                time.sleep(3600)  # 1 hour
            else:
                print("No additional delegation needed")
                time.sleep(3600)

# Example usage
def main():
    manager = TronDelegationManager('YOUR_API_KEY')
    strategy = SmartDelegationStrategy(manager)
    
    # 1. Simple delegation
    print("=== Simple Delegation ===")
    simple_tx = manager.delegate_resources(
        'TOwnerAddress...',
        'TReceiverAddress...',
        1000,  # 1000 TRX
        'ENERGY',
        lock=True
    )
    print(f"Transaction ID: {simple_tx['txID']}")
    
    # 2. Analyze delegation needs
    print("\n=== Delegation Analysis ===")
    analysis = manager.analyze_delegation_needs('TReceiverAddress...', days=7)
    print(f"Energy needs: {analysis['energy']['recommended_delegation_trx']:.2f} TRX")
    print(f"Bandwidth needs: {analysis['bandwidth']['recommended_delegation_trx']:.2f} TRX")
    
    # 3. Batch delegation for gaming
    print("\n=== Gaming Delegation ===")
    gaming_results = strategy.delegate_for_gaming(
        'TOwnerAddress...',
        ['TPlayer1...', 'TPlayer2...', 'TPlayer3...']
    )
    
    for result in gaming_results:
        if result['success']:
            print(f"✓ {result['receiver']}: {result['resource']} - TX: {result['txID'][:8]}...")
        else:
            print(f"✗ {result['receiver']}: {result['error']}")
    
    # 4. Check existing delegations
    print("\n=== Existing Delegations ===")
    index = manager.get_delegation_index('TOwnerAddress...')
    
    if index.get('toAccounts'):
        for account in index['toAccounts']:
            detail = manager.get_delegation_detail('TOwnerAddress...', account)
            print(f"To {account}:")
            for delegation in detail.get('delegatedResource', []):
                print(f"  - {delegation['frozen_balance_for_energy']/1_000_000:.2f} TRX for ENERGY")
                print(f"  - {delegation['frozen_balance_for_bandwidth']/1_000_000:.2f} TRX for BANDWIDTH")

if __name__ == "__main__":
    main()
```

## Delegation Flow

```mermaid
graph LR
    A[Owner Stakes TRX] --> B[Resources Available]
    B --> C[Delegate to Receiver]
    C --> D[Receiver Uses Resources]
    D --> E[Resources Consumed]
    E --> F[Owner Can Reclaim]
    
    style A fill:#4CAF50
    style C fill:#2196F3
    style D fill:#FF9800
```

## Best Practices

### 1. **Calculate Before Delegating**

```javascript
// Always analyze needs first
const needs = await analyzeNeeds(receiverAddress);
const delegateAmount = Math.ceil(needs.energy.deficit / 28.5);
```

### 2. **Use Locks Strategically**

- Lock for stable, long-term delegations
- Keep unlocked for flexible, short-term needs
- Consider 3-day default lock period

### 3. **Monitor Resource Usage**

- Track receiver's consumption patterns
- Adjust delegations based on actual usage
- Implement alerts for high usage

### 4. **Batch Operations**

- Group multiple delegations together
- Reduces transaction overhead
- Easier management and tracking

## Common Errors

| Error                         | Description                             | Solution                    |
| ----------------------------- | --------------------------------------- | --------------------------- |
| `Insufficient staked balance` | Not enough staked resources             | Stake more TRX first        |
| `Invalid resource type`       | Must be BANDWIDTH or ENERGY             | Use correct resource string |
| `Receiver address invalid`    | Malformed receiver address              | Verify base58 format        |
| `Already delegated`           | Resources already delegated to receiver | Check existing delegations  |

## Use Cases

- **DApp Support**: Provide resources for users to interact with your DApp
- **Gaming**: Enable free gameplay by covering resource costs
- **DeFi Trading**: Support traders with energy for smart contract calls
- **Onboarding**: Help new users get started without staking
- **Resource Rental**: Commercial resource delegation services

## Related Methods

- [wallet/undelegateresource](https://www.dwellir.com/docs/tron/wallet-undelegateresource) - Reclaim delegated resources
- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Stake TRX for resources
- [wallet/getaccountresource](https://www.dwellir.com/docs/tron/wallet-getaccountresource) - View resource limits

---

## wallet/estimateenergy - Estimate TRON Energy Co...

# wallet/estimateenergy - Estimate TRON Energy Co...

**Dwellir's TRON endpoints** provide accurate energy estimation to help you optimize smart contract execution costs.
Plan your transactions and avoid energy shortfalls with precise cost forecasting.

[Optimize your energy usage](https://dashboard.dwellir.com/register)

Estimates the energy consumption required for executing a smart contract call on the TRON network. Essential for cost planning and resource management.

## When to Use This Method

`wallet/estimateenergy` is essential for:

- **Cost Planning** - Estimate transaction costs before execution
- **Resource Management** - Plan energy requirements for smart contracts
- **User Interfaces** - Display estimated costs to users
- **Batch Operations** - Calculate total energy needed for multiple calls
- **Energy Optimization** - Compare different execution strategies

## Request Parameters

- `owner_address` (`string, required`): Address that will execute the contract call Example: `"TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh"`
- `contract_address` (`string, required`): Smart contract address to call Example: `"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"` (USDT)
- `function_selector` (`string, required`): Function signature to estimate Example: `"transfer(address,uint256)"`
- `parameter` (`string, optional`): Hex-encoded function parameters Example: `"0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240"`
- `call_value` (`integer, optional`): TRX amount to send (in SUN) for payable functions Default: `0`
- `visible` (`boolean, optional`): `true` - Use Base58 address format `false` - Use hex address format

## Request Example

```json
{
  "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "function_selector": "transfer(address,uint256)",
  "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240",
  "visible": true
}
```

## Response Fields

- `result` (`OBJECT, required`): `energy_required` - Estimated energy consumption `result` - Execution success/failure simulation `energy_used` - Base energy used for calculation

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Estimate energy for TRC20 transfer
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/estimateenergy" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "transfer(address,uint256)",
    "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240",
    "visible": true
  }'

# Extract energy estimation and calculate cost
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/estimateenergy" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "transfer(address,uint256)",
    "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240",
    "visible": true
  }' | jq '{
    energy_required: .energy_required,
    will_succeed: .result.result,
    estimated_cost_trx: (.energy_required * 0.00014),
    estimated_cost_sun: (.energy_required * 0.00014 * 1000000 | floor)
  }'

# Batch energy estimation script
#!/bin/bash
API_KEY="YOUR_API_KEY"
OWNER_ADDRESS="TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh"

# Function to estimate energy
estimate_energy() {
  local contract_address=$1
  local function_selector=$2
  local parameters=$3
  local call_value=${4:-0}
  
  curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/estimateenergy" \
    -H "Content-Type: application/json" \
    -d "{
      \"owner_address\": \"$OWNER_ADDRESS\",
      \"contract_address\": \"$contract_address\",
      \"function_selector\": \"$function_selector\",
      \"parameter\": \"$parameters\",
      \"call_value\": $call_value,
      \"visible\": true
    }"
}

# Function to calculate costs
calculate_costs() {
  local energy_required=$1
  local energy_cost_per_unit=0.00014
  
  local cost_trx=$(echo "scale=8; $energy_required * $energy_cost_per_unit" | bc -l)
  local cost_sun=$(echo "scale=0; $cost_trx * 1000000 / 1" | bc -l)
  
  echo "Energy required: $energy_required"
  echo "Cost in TRX: $cost_trx"
  echo "Cost in SUN: $cost_sun"
}

# Function to check if execution can be free
check_free_execution() {
  local address=$1
  local energy_needed=$2
  
  local resources=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/getaccountresource" \
    -H "Content-Type: application/json" \
    -d "{\"address\": \"$address\", \"visible\": true}")
  
  local energy_limit=$(echo "$resources" | jq -r '.EnergyLimit // 0')
  local energy_used=$(echo "$resources" | jq -r '.EnergyUsed // 0')
  local available_energy=$((energy_limit - energy_used))
  
  if [ "$available_energy" -ge "$energy_needed" ]; then
    echo "✅ Can execute for free using staked energy"
    echo "Available energy: $available_energy"
  else
    echo "❌ Insufficient staked energy"
    echo "Available: $available_energy, Needed: $energy_needed"
    echo "Shortfall: $((energy_needed - available_energy))"
  fi
}

# Estimate common operations
estimate_common_operations() {
  local contract_address=$1
  
  echo "=== Energy Estimation for Common Operations ==="
  echo "Contract: $contract_address"
  echo "Owner: $OWNER_ADDRESS"
  echo ""
  
  # TRC20 Transfer
  echo "1. TRC20 Transfer"
  local transfer_params="0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240"
  local transfer_result=$(estimate_energy "$contract_address" "transfer(address,uint256)" "$transfer_params")
  local transfer_energy=$(echo "$transfer_result" | jq -r '.energy_required // 0')
  
  calculate_costs "$transfer_energy"
  check_free_execution "$OWNER_ADDRESS" "$transfer_energy"
  echo ""
  
  # TRC20 Approve
  echo "2. TRC20 Approve"
  local approve_result=$(estimate_energy "$contract_address" "approve(address,uint256)" "$transfer_params")
  local approve_energy=$(echo "$approve_result" | jq -r '.energy_required // 0')
  
  calculate_costs "$approve_energy"
  check_free_execution "$OWNER_ADDRESS" "$approve_energy"
  echo ""
  
  # Balance query (view function)
  echo "3. Balance Query (view function)"
  local balance_params="0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863"
  local balance_result=$(estimate_energy "$contract_address" "balanceOf(address)" "$balance_params")
  local balance_energy=$(echo "$balance_result" | jq -r '.energy_required // 0')
  
  calculate_costs "$balance_energy"
  echo ""
  
  # Summary
  local total_energy=$((transfer_energy + approve_energy + balance_energy))
  echo "=== Summary ==="
  echo "Total energy for all operations: $total_energy"
  calculate_costs "$total_energy"
}

# Energy optimization advisor
energy_optimization_advisor() {
  local total_energy_needed=$1
  
  echo "=== Energy Optimization Advisor ==="
  echo "Total energy needed: $total_energy_needed"
  echo ""
  
  # Calculate different strategies
  local pay_trx_cost=$(echo "scale=6; $total_energy_needed * 0.00014" | bc -l)
  local stake_trx_needed=$(echo "scale=2; $total_energy_needed / 4000" | bc -l)
  local rent_cost=$(echo "scale=6; $pay_trx_cost * 0.7" | bc -l)
  
  echo "Strategy Options:"
  echo ""
  echo "1. Pay with TRX"
  echo "   Cost: $pay_trx_cost TRX"
  echo "   Pros: Immediate execution, no staking required"
  echo "   Cons: Higher cost per transaction"
  echo ""
  echo "2. Stake TRX for Energy"
  echo "   Stake needed: ~$stake_trx_needed TRX"
  echo "   Pros: Reusable energy, long-term savings"
  echo "   Cons: TRX locked for 3 days"
  echo ""
  echo "3. Rent Energy"
  echo "   Cost: ~$rent_cost TRX"
  echo "   Pros: Lower cost than direct payment"
  echo "   Cons: One-time use, requires third-party"
  echo ""
  
  # Recommendation
  if (( $(echo "$pay_trx_cost < 1" | bc -l) )); then
    echo "💡 Recommendation: Pay with TRX (low cost)"
  elif (( $(echo "$stake_trx_needed < 100" | bc -l) )); then
    echo "💡 Recommendation: Consider staking TRX for energy"
  else
    echo "💡 Recommendation: Rent energy for better cost efficiency"
  fi
}

# Batch estimation for multiple contracts
batch_estimate() {
  local contracts_file=$1
  
  if [ ! -f "$contracts_file" ]; then
    echo "Error: Contracts file not found: $contracts_file"
    echo "Create a file with format: CONTRACT_ADDRESS:FUNCTION_SELECTOR:PARAMETERS"
    return 1
  fi
  
  echo "=== Batch Energy Estimation ==="
  echo "Processing contracts from: $contracts_file"
  echo ""
  
  local total_energy=0
  local operation_count=0
  
  while IFS=':' read -r contract_address function_selector parameters; do
    # Skip empty lines
    [ -z "$contract_address" ] && continue
    
    ((operation_count++))
    echo "Operation $operation_count: $function_selector"
    
    local result=$(estimate_energy "$contract_address" "$function_selector" "$parameters")
    local energy=$(echo "$result" | jq -r '.energy_required // 0')
    local will_succeed=$(echo "$result" | jq -r '.result.result // false')
    
    echo "  Energy: $energy"
    echo "  Will succeed: $will_succeed"
    
    total_energy=$((total_energy + energy))
    echo ""
  done < "$contracts_file"
  
  echo "=== Batch Summary ==="
  echo "Total operations: $operation_count"
  echo "Total energy required: $total_energy"
  
  if [ "$total_energy" -gt 0 ]; then
    calculate_costs "$total_energy"
    energy_optimization_advisor "$total_energy"
  fi
}

# Usage examples
case "${1:-common}" in
  "common")
    # Default: estimate common operations for USDT
    estimate_common_operations "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
    ;;
  "single")
    # Estimate single operation
    if [ $# -lt 3 ]; then
      echo "Usage: $0 single CONTRACT_ADDRESS FUNCTION_SELECTOR [PARAMETERS]"
      exit 1
    fi
    
    local result=$(estimate_energy "$2" "$3" "${4:-}")
    local energy=$(echo "$result" | jq -r '.energy_required // 0')
    
    echo "Energy estimation result:"
    echo "$result" | jq .
    echo ""
    calculate_costs "$energy"
    check_free_execution "$OWNER_ADDRESS" "$energy"
    ;;
  "batch")
    # Batch estimation
    batch_estimate "$2"
    ;;
  "optimize")
    # Energy optimization for specific amount
    energy_optimization_advisor "$2"
    ;;
  *)
    echo "Usage: $0 {common|single|batch|optimize} [args...]"
    echo ""
    echo "Commands:"
    echo "  common                                  - Estimate common TRC20 operations"
    echo "  single CONTRACT FUNCTION [PARAMS]      - Estimate single operation"
    echo "  batch CONTRACTS_FILE                   - Batch estimation from file"
    echo "  optimize ENERGY_AMOUNT                 - Get optimization advice"
    ;;
esac
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Estimate energy for smart contract call
async function estimateEnergy(ownerAddress, contractAddress, functionSelector, parameters = '', callValue = 0) {
  const response = await fetch(`${TRON_API}/wallet/estimateenergy`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      owner_address: ownerAddress,
      contract_address: contractAddress,
      function_selector: functionSelector,
      parameter: parameters,
      call_value: callValue,
      visible: true
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Energy estimation and cost calculator
class TronEnergyEstimator {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
    
    // Energy costs (approximate rates)
    this.energyCostPerUnit = 0.00014; // TRX per energy unit (variable)
    this.sunPerTrx = 1_000_000;
  }
  
  async estimateContractCall(ownerAddress, contractAddress, functionSelector, parameters = '', callValue = 0) {
    try {
      const estimation = await this.estimateEnergy(ownerAddress, contractAddress, functionSelector, parameters, callValue);
      
      const energyRequired = estimation.energy_required || 0;
      const willSucceed = estimation.result?.result !== false;
      
      return {
        success: true,
        energyRequired,
        willSucceed,
        estimatedCostTRX: this.calculateCostInTRX(energyRequired),
        estimatedCostSUN: this.calculateCostInSUN(energyRequired),
        canExecuteForFree: await this.canExecuteForFree(ownerAddress, energyRequired),
        recommendation: await this.generateRecommendation(ownerAddress, energyRequired),
        rawEstimation: estimation
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
        energyRequired: 0,
        estimatedCostTRX: 0
      };
    }
  }
  
  async estimateEnergy(ownerAddress, contractAddress, functionSelector, parameters, callValue) {
    const response = await fetch(`${this.apiUrl}/wallet/estimateenergy`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        owner_address: ownerAddress,
        contract_address: contractAddress,
        function_selector: functionSelector,
        parameter: parameters,
        call_value: callValue,
        visible: true
      })
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    return await response.json();
  }
  
  calculateCostInTRX(energyRequired) {
    return energyRequired * this.energyCostPerUnit;
  }
  
  calculateCostInSUN(energyRequired) {
    return Math.floor(energyRequired * this.energyCostPerUnit * this.sunPerTrx);
  }
  
  async canExecuteForFree(ownerAddress, energyRequired) {
    try {
      // Check if user has enough energy staked
      const resourceResponse = await fetch(`${this.apiUrl}/wallet/getaccountresource`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ address: ownerAddress, visible: true })
      });
      
      const resources = await resourceResponse.json();
      const availableEnergy = (resources.EnergyLimit || 0) - (resources.EnergyUsed || 0);
      
      return availableEnergy >= energyRequired;
    } catch (error) {
      console.warn('Could not check energy availability:', error);
      return false;
    }
  }
  
  async generateRecommendation(ownerAddress, energyRequired) {
    const canExecuteForFree = await this.canExecuteForFree(ownerAddress, energyRequired);
    const costTRX = this.calculateCostInTRX(energyRequired);
    
    if (canExecuteForFree) {
      return {
        type: 'success',
        message: 'Transaction can execute for free using staked energy',
        action: 'Proceed with transaction'
      };
    } else if (costTRX < 1) {
      return {
        type: 'low_cost',
        message: `Transaction will cost ${costTRX.toFixed(6)} TRX`,
        action: 'Consider proceeding with TRX payment'
      };
    } else if (costTRX < 10) {
      return {
        type: 'moderate_cost',
        message: `Transaction will cost ${costTRX.toFixed(3)} TRX`,
        action: 'Consider staking TRX for energy to reduce costs'
      };
    } else {
      return {
        type: 'high_cost',
        message: `High cost: ${costTRX.toFixed(2)} TRX`,
        action: 'Strongly recommend staking TRX for energy or renting energy'
      };
    }
  }
  
  // Estimate energy for common contract operations
  async estimateCommonOperations(ownerAddress, contractAddress) {
    const operations = [
      { name: 'Transfer TRC20', selector: 'transfer(address,uint256)', params: this.encodeTransferParams('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000) },
      { name: 'Approve TRC20', selector: 'approve(address,uint256)', params: this.encodeApprovalParams('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000) },
      { name: 'Get Balance', selector: 'balanceOf(address)', params: this.encodeAddressParam('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN') }
    ];
    
    const estimates = [];
    
    for (const op of operations) {
      try {
        const estimate = await this.estimateContractCall(
          ownerAddress,
          contractAddress,
          op.selector,
          op.params
        );
        
        estimates.push({
          operation: op.name,
          ...estimate
        });
      } catch (error) {
        estimates.push({
          operation: op.name,
          success: false,
          error: error.message,
          energyRequired: 0
        });
      }
    }
    
    return estimates;
  }
  
  // Parameter encoding helpers
  encodeAddressParam(address) {
    // Simplified encoding - use proper library in production
    return '0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863';
  }
  
  encodeTransferParams(toAddress, amount) {
    // Simplified encoding for transfer(address,uint256)
    const addressParam = this.encodeAddressParam(toAddress);
    const amountParam = amount.toString(16).padStart(64, '0');
    return addressParam + amountParam;
  }
  
  encodeApprovalParams(spenderAddress, amount) {
    // Same as transfer params for approve(address,uint256)
    return this.encodeTransferParams(spenderAddress, amount);
  }
}

// Batch energy estimation for multiple operations
class TronBatchEnergyEstimator {
  constructor(apiKey) {
    this.estimator = new TronEnergyEstimator(apiKey);
  }
  
  async estimateBatchOperations(operations) {
    const results = [];
    let totalEnergyRequired = 0;
    let totalCostTRX = 0;
    let allWillSucceed = true;
    
    for (const op of operations) {
      try {
        const estimate = await this.estimator.estimateContractCall(
          op.ownerAddress,
          op.contractAddress,
          op.functionSelector,
          op.parameters || '',
          op.callValue || 0
        );
        
        results.push({
          operation: op.name || 'Unknown',
          ...estimate
        });
        
        if (estimate.success) {
          totalEnergyRequired += estimate.energyRequired;
          totalCostTRX += estimate.estimatedCostTRX;
          allWillSucceed = allWillSucceed && estimate.willSucceed;
        }
        
      } catch (error) {
        results.push({
          operation: op.name || 'Unknown',
          success: false,
          error: error.message
        });
        allWillSucceed = false;
      }
    }
    
    return {
      operations: results,
      summary: {
        totalOperations: operations.length,
        successfulEstimations: results.filter(r => r.success).length,
        totalEnergyRequired,
        totalCostTRX,
        totalCostSUN: Math.floor(totalCostTRX * 1_000_000),
        allWillSucceed,
        averageEnergyPerOperation: totalEnergyRequired / operations.length
      }
    };
  }
}

// Energy optimization advisor
class TronEnergyOptimizer {
  constructor(apiKey) {
    this.estimator = new TronEnergyEstimator(apiKey);
  }
  
  async analyzeEnergyStrategy(ownerAddress, plannedOperations) {
    const batchEstimator = new TronBatchEnergyEstimator(this.apiKey);
    const estimates = await batchEstimator.estimateBatchOperations(plannedOperations);
    
    const totalEnergyNeeded = estimates.summary.totalEnergyRequired;
    const totalCostTRX = estimates.summary.totalCostTRX;
    
    // Get current energy resources
    const canExecuteForFree = await this.estimator.canExecuteForFree(ownerAddress, totalEnergyNeeded);
    
    const strategies = [
      {
        name: 'Pay with TRX',
        cost: totalCostTRX,
        description: `Pay ${totalCostTRX.toFixed(6)} TRX for energy`,
        pros: ['No upfront staking required', 'Immediate execution'],
        cons: ['Higher cost per transaction', 'No reusable energy']
      },
      {
        name: 'Stake TRX for Energy',
        cost: totalEnergyNeeded / 4000, // Approximate staking ratio
        description: `Stake ~${(totalEnergyNeeded / 4000).toFixed(2)} TRX for energy`,
        pros: ['Reusable energy', 'Lower long-term costs', 'Supports network'],
        cons: ['TRX locked for 3 days', 'Upfront capital required']
      },
      {
        name: 'Rent Energy',
        cost: totalCostTRX * 0.7, // Assume 30% savings
        description: `Rent energy for ~${(totalCostTRX * 0.7).toFixed(6)} TRX`,
        pros: ['Lower cost than direct payment', 'No long-term commitment'],
        cons: ['One-time use', 'Requires third-party platform']
      }
    ];
    
    // Sort strategies by cost
    strategies.sort((a, b) => a.cost - b.cost);
    
    return {
      analysis: {
        totalEnergyNeeded,
        totalCostTRX,
        canExecuteForFree,
        operationCount: plannedOperations.length
      },
      strategies,
      recommendation: canExecuteForFree ? 
        'Use existing staked energy - execution will be free' :
        strategies[0].name, // Cheapest strategy
      operationDetails: estimates
    };
  }
}

// Usage examples
(async () => {
  try {
    const estimator = new TronEnergyEstimator('YOUR_API_KEY');
    
    // Estimate single operation
    const estimate = await estimator.estimateContractCall(
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
      'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT
      'transfer(address,uint256)',
      estimator.encodeTransferParams('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000)
    );
    
    console.log('Energy Estimate:', estimate.energyRequired);
    console.log('Cost:', estimate.estimatedCostTRX, 'TRX');
    console.log('Can execute for free:', estimate.canExecuteForFree);
    
    // Batch estimation
    const batchEstimator = new TronBatchEnergyEstimator('YOUR_API_KEY');
    const operations = [
      {
        name: 'USDT Transfer',
        ownerAddress: 'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
        contractAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
        functionSelector: 'transfer(address,uint256)',
        parameters: estimator.encodeTransferParams('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000)
      }
    ];
    
    const batchResults = await batchEstimator.estimateBatchOperations(operations);
    console.log('Batch total energy:', batchResults.summary.totalEnergyRequired);
    
    // Energy optimization analysis
    const optimizer = new TronEnergyOptimizer('YOUR_API_KEY');
    const strategy = await optimizer.analyzeEnergyStrategy('TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh', operations);
    console.log('Recommended strategy:', strategy.recommendation);
    console.log('Best option cost:', strategy.strategies[0].cost, 'TRX');
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
from typing import Dict, List, Optional

class TronEnergyEstimator:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
        
        # Energy costs (approximate rates)
        self.energy_cost_per_unit = 0.00014  # TRX per energy unit
        self.sun_per_trx = 1_000_000
    
    def estimate_energy(self, owner_address: str, contract_address: str, 
                       function_selector: str, parameters: str = '', call_value: int = 0) -> Dict:
        """Estimate energy for smart contract call"""
        url = f"{self.base_url}/wallet/estimateenergy"
        
        payload = {
            "owner_address": owner_address,
            "contract_address": contract_address,
            "function_selector": function_selector,
            "parameter": parameters,
            "call_value": call_value,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def estimate_contract_call(self, owner_address: str, contract_address: str,
                              function_selector: str, parameters: str = '', call_value: int = 0) -> Dict:
        """Estimate contract call with cost analysis"""
        try:
            estimation = self.estimate_energy(owner_address, contract_address, function_selector, parameters, call_value)
            
            energy_required = estimation.get('energy_required', 0)
            will_succeed = estimation.get('result', {}).get('result', True)
            
            return {
                'success': True,
                'energy_required': energy_required,
                'will_succeed': will_succeed,
                'estimated_cost_trx': self.calculate_cost_in_trx(energy_required),
                'estimated_cost_sun': self.calculate_cost_in_sun(energy_required),
                'can_execute_for_free': self.can_execute_for_free(owner_address, energy_required),
                'recommendation': self.generate_recommendation(owner_address, energy_required),
                'raw_estimation': estimation
            }
        except Exception as e:
            return {
                'success': False,
                'error': str(e),
                'energy_required': 0,
                'estimated_cost_trx': 0
            }
    
    def calculate_cost_in_trx(self, energy_required: int) -> float:
        """Calculate cost in TRX"""
        return energy_required * self.energy_cost_per_unit
    
    def calculate_cost_in_sun(self, energy_required: int) -> int:
        """Calculate cost in SUN"""
        return int(energy_required * self.energy_cost_per_unit * self.sun_per_trx)
    
    def can_execute_for_free(self, owner_address: str, energy_required: int) -> bool:
        """Check if user has enough staked energy"""
        try:
            url = f"{self.base_url}/wallet/getaccountresource"
            response = requests.post(url, headers=self.headers, json={
                "address": owner_address,
                "visible": True
            })
            
            resources = response.json()
            available_energy = (resources.get('EnergyLimit', 0) - resources.get('EnergyUsed', 0))
            
            return available_energy >= energy_required
        except Exception:
            return False
    
    def generate_recommendation(self, owner_address: str, energy_required: int) -> Dict:
        """Generate recommendation based on energy needs"""
        can_execute_for_free = self.can_execute_for_free(owner_address, energy_required)
        cost_trx = self.calculate_cost_in_trx(energy_required)
        
        if can_execute_for_free:
            return {
                'type': 'success',
                'message': 'Transaction can execute for free using staked energy',
                'action': 'Proceed with transaction'
            }
        elif cost_trx < 1:
            return {
                'type': 'low_cost',
                'message': f'Transaction will cost {cost_trx:.6f} TRX',
                'action': 'Consider proceeding with TRX payment'
            }
        elif cost_trx < 10:
            return {
                'type': 'moderate_cost',
                'message': f'Transaction will cost {cost_trx:.3f} TRX',
                'action': 'Consider staking TRX for energy to reduce costs'
            }
        else:
            return {
                'type': 'high_cost',
                'message': f'High cost: {cost_trx:.2f} TRX',
                'action': 'Strongly recommend staking TRX for energy or renting energy'
            }
    
    def estimate_common_operations(self, owner_address: str, contract_address: str) -> List[Dict]:
        """Estimate energy for common contract operations"""
        operations = [
            {
                'name': 'Transfer TRC20',
                'selector': 'transfer(address,uint256)',
                'params': self.encode_transfer_params('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000)
            },
            {
                'name': 'Approve TRC20',
                'selector': 'approve(address,uint256)',
                'params': self.encode_approval_params('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000)
            },
            {
                'name': 'Get Balance',
                'selector': 'balanceOf(address)',
                'params': self.encode_address_param('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN')
            }
        ]
        
        estimates = []
        
        for op in operations:
            try:
                estimate = self.estimate_contract_call(
                    owner_address,
                    contract_address,
                    op['selector'],
                    op['params']
                )
                estimate['operation'] = op['name']
                estimates.append(estimate)
            except Exception as e:
                estimates.append({
                    'operation': op['name'],
                    'success': False,
                    'error': str(e),
                    'energy_required': 0
                })
        
        return estimates
    
    # Parameter encoding helpers (simplified)
    def encode_address_param(self, address: str) -> str:
        """Encode address parameter"""
        # Simplified encoding - use proper library in production
        return '0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863'
    
    def encode_transfer_params(self, to_address: str, amount: int) -> str:
        """Encode transfer parameters"""
        address_param = self.encode_address_param(to_address)
        amount_param = format(amount, '064x')
        return address_param + amount_param
    
    def encode_approval_params(self, spender_address: str, amount: int) -> str:
        """Encode approval parameters"""
        return self.encode_transfer_params(spender_address, amount)

class TronBatchEnergyEstimator:
    def __init__(self, api_key: str):
        self.estimator = TronEnergyEstimator(api_key)
    
    def estimate_batch_operations(self, operations: List[Dict]) -> Dict:
        """Estimate energy for multiple operations"""
        results = []
        total_energy_required = 0
        total_cost_trx = 0
        all_will_succeed = True
        
        for op in operations:
            try:
                estimate = self.estimator.estimate_contract_call(
                    op['owner_address'],
                    op['contract_address'],
                    op['function_selector'],
                    op.get('parameters', ''),
                    op.get('call_value', 0)
                )
                
                estimate['operation'] = op.get('name', 'Unknown')
                results.append(estimate)
                
                if estimate['success']:
                    total_energy_required += estimate['energy_required']
                    total_cost_trx += estimate['estimated_cost_trx']
                    all_will_succeed = all_will_succeed and estimate['will_succeed']
                
            except Exception as e:
                results.append({
                    'operation': op.get('name', 'Unknown'),
                    'success': False,
                    'error': str(e)
                })
                all_will_succeed = False
        
        return {
            'operations': results,
            'summary': {
                'total_operations': len(operations),
                'successful_estimations': len([r for r in results if r.get('success')]),
                'total_energy_required': total_energy_required,
                'total_cost_trx': total_cost_trx,
                'total_cost_sun': int(total_cost_trx * 1_000_000),
                'all_will_succeed': all_will_succeed,
                'average_energy_per_operation': total_energy_required / len(operations) if operations else 0
            }
        }

class TronEnergyOptimizer:
    def __init__(self, api_key: str):
        self.estimator = TronEnergyEstimator(api_key)
    
    def analyze_energy_strategy(self, owner_address: str, planned_operations: List[Dict]) -> Dict:
        """Analyze optimal energy strategy for planned operations"""
        batch_estimator = TronBatchEnergyEstimator(self.estimator.api_key)
        estimates = batch_estimator.estimate_batch_operations(planned_operations)
        
        total_energy_needed = estimates['summary']['total_energy_required']
        total_cost_trx = estimates['summary']['total_cost_trx']
        
        can_execute_for_free = self.estimator.can_execute_for_free(owner_address, total_energy_needed)
        
        strategies = [
            {
                'name': 'Pay with TRX',
                'cost': total_cost_trx,
                'description': f'Pay {total_cost_trx:.6f} TRX for energy',
                'pros': ['No upfront staking required', 'Immediate execution'],
                'cons': ['Higher cost per transaction', 'No reusable energy']
            },
            {
                'name': 'Stake TRX for Energy',
                'cost': total_energy_needed / 4000,  # Approximate staking ratio
                'description': f'Stake ~{total_energy_needed / 4000:.2f} TRX for energy',
                'pros': ['Reusable energy', 'Lower long-term costs', 'Supports network'],
                'cons': ['TRX locked for 3 days', 'Upfront capital required']
            },
            {
                'name': 'Rent Energy',
                'cost': total_cost_trx * 0.7,  # Assume 30% savings
                'description': f'Rent energy for ~{total_cost_trx * 0.7:.6f} TRX',
                'pros': ['Lower cost than direct payment', 'No long-term commitment'],
                'cons': ['One-time use', 'Requires third-party platform']
            }
        ]
        
        # Sort strategies by cost
        strategies.sort(key=lambda x: x['cost'])
        
        return {
            'analysis': {
                'total_energy_needed': total_energy_needed,
                'total_cost_trx': total_cost_trx,
                'can_execute_for_free': can_execute_for_free,
                'operation_count': len(planned_operations)
            },
            'strategies': strategies,
            'recommendation': 'Use existing staked energy - execution will be free' if can_execute_for_free else strategies[0]['name'],
            'operation_details': estimates
        }

# Usage examples
if __name__ == "__main__":
    estimator = TronEnergyEstimator('YOUR_API_KEY')
    
    try:
        # Estimate single operation
        estimate = estimator.estimate_contract_call(
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
            'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',  # USDT
            'transfer(address,uint256)',
            estimator.encode_transfer_params('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000)
        )
        
        print(f"Energy Estimate: {estimate['energy_required']}")
        print(f"Cost: {estimate['estimated_cost_trx']} TRX")
        print(f"Can execute for free: {estimate['can_execute_for_free']}")
        print(f"Recommendation: {estimate['recommendation']['message']}")
        
        # Batch estimation
        batch_estimator = TronBatchEnergyEstimator('YOUR_API_KEY')
        operations = [
            {
                'name': 'USDT Transfer',
                'owner_address': 'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
                'contract_address': 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
                'function_selector': 'transfer(address,uint256)',
                'parameters': estimator.encode_transfer_params('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', 1000000)
            }
        ]
        
        batch_results = batch_estimator.estimate_batch_operations(operations)
        print(f"\nBatch total energy: {batch_results['summary']['total_energy_required']}")
        print(f"Total cost: {batch_results['summary']['total_cost_trx']} TRX")
        
        # Energy optimization analysis
        optimizer = TronEnergyOptimizer('YOUR_API_KEY')
        strategy = optimizer.analyze_energy_strategy('TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh', operations)
        
        print(f"\nRecommended strategy: {strategy['recommendation']}")
        print(f"Best option cost: {strategy['strategies'][0]['cost']} TRX")
        print(f"Description: {strategy['strategies'][0]['description']}")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful Energy Estimation

```json
{
  "energy_required": 13326,
  "result": {
    "result": true
  },
  "energy_used": 13326
}
```

### Failed Estimation (Insufficient Balance)

```json
{
  "energy_required": 0,
  "result": {
    "result": false,
    "code": "REVERT",
    "message": "revert Insufficient balance"
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/freezebalancev2 - Stake TRX for Resources

# wallet/freezebalancev2 - Stake TRX for Resources

**Dwellir's TRON infrastructure** supports the latest Stake 2.0 mechanism for efficient resource management.
Stake TRX to get bandwidth/energy while earning rewards and voting rights.

[Start staking TRX](https://dashboard.dwellir.com/register)

Freeze (stake) TRX balance to obtain bandwidth or energy resources using the Stake 2.0 mechanism. Staked TRX earns rewards and provides voting power for Super Representatives.

## Use Cases

`wallet/freezebalancev2` is essential for:

- **Resource Acquisition** - Get bandwidth for transactions
- **Energy Generation** - Power smart contract interactions
- **Reward Earning** - Earn staking rewards (\~4-7% APR)
- **Governance Participation** - Gain voting power for SRs
- **DApp Operations** - Ensure smooth contract execution

## Request Parameters

- `owner_address` (`string, required`): Address staking TRX (Base58 or Hex)
- `frozen_balance` (`number, required`): Amount to stake in SUN (1 TRX = 1,000,000 SUN)
- `resource` (`string, required`): Resource type: "BANDWIDTH" or "ENERGY"
- `visible` (`boolean, optional`): Use Base58 format (default: true)
- `permission_id` (`number, optional`): Permission ID for multi-sig accounts

## Request Example

```json
{
  "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
  "frozen_balance": 10000000000,
  "resource": "ENERGY",
  "visible": true
}
```

## Response Fields

- `txid` (`string, required`): Transaction ID
- `visible` (`boolean, required`): Address format used
- `raw_data` (`object, required`): Transaction raw data
- `raw_data.contract` (`array, required`): Contract details
- `raw_data.ref_block_bytes` (`string, required`): Reference block bytes
- `raw_data.ref_block_hash` (`string, required`): Reference block hash
- `raw_data.expiration` (`number, required`): Transaction expiration time
- `raw_data.timestamp` (`number, required`): Transaction timestamp

## Successful Response

```json
{
  "visible": true,
  "txID": "7a2e5c8f9b3d1a4e6f8c2b5d9e1a3f7c4b8d2e6a9c3f5b8d1e4a7c9f2b5d8e",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
            "frozen_balance": 10000000000,
            "resource": "ENERGY"
          },
          "type_url": "type.googleapis.com/protocol.FreezeBalanceV2Contract"
        },
        "type": "FreezeBalanceV2Contract"
      }
    ],
    "ref_block_bytes": "7ac7",
    "ref_block_hash": "4d9bb8f8c9c59ac3",
    "expiration": 1702456849000,
    "timestamp": 1702456789000,
    "fee_limit": 1000000000
  },
  "raw_data_hex": "0a0207ac722..."
}
```

## Error Responses

### Error 1

- Code: `INVALID_RESOURCE`
- Description: Invalid resource type

### Error 2

- Code: `INSUFFICIENT_BALANCE`
- Description: Not enough TRX

### Error 3

- Code: `ACCOUNT_NOT_FOUND`
- Description: Address doesn't exist

### Error 4

- Code: `TAPOS_ERROR`
- Description: Transaction expired

## Implementation Examples

cURL
JavaScript
Python

```bash
# Freeze TRX for ENERGY
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/freezebalancev2" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "frozen_balance": 10000000000,
    "resource": "ENERGY",
    "visible": true
  }'

# Freeze TRX for BANDWIDTH
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/freezebalancev2" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "frozen_balance": 5000000000,
    "resource": "BANDWIDTH",
    "visible": true
  }'

# Parse response with jq
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/freezebalancev2" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "frozen_balance": 10000000000,
    "resource": "ENERGY",
    "visible": true
  }' | jq '{
    txid: .txid,
    resource: .raw_data.contract[0].parameter.value.resource,
    amount_sun: .raw_data.contract[0].parameter.value.frozen_balance,
    amount_trx: (.raw_data.contract[0].parameter.value.frozen_balance / 1000000),
    expiration: .raw_data.expiration
  }'

# Script to calculate and stake optimal amounts
#!/bin/bash
API_KEY="YOUR_API_KEY"
ADDRESS="TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"

# Function to stake TRX
stake_trx() {
  local amount_sun=$1
  local resource=$2
  
  echo "Staking $((amount_sun / 1000000)) TRX for $resource..."
  
  response=$(curl -s -X POST \
    "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/freezebalancev2" \
    -H "Content-Type: application/json" \
    -d "{
      \"owner_address\": \"$ADDRESS\",
      \"frozen_balance\": $amount_sun,
      \"resource\": \"$resource\",
      \"visible\": true
    }")
  
  txid=$(echo "$response" | jq -r '.txid')
  
  if [ "$txid" != "null" ]; then
    echo "✓ Transaction created: $txid"
    echo "  Please sign and broadcast this transaction"
  else
    echo "✗ Failed to create transaction"
    echo "$response" | jq .
  fi
}

# Calculate resources needed
echo "=== Resource Staking Calculator ==="
echo

read -p "Daily transactions expected: " daily_tx
read -p "Daily smart contract calls expected: " daily_contracts

# Calculate requirements (approximate)
bandwidth_needed=$((daily_tx * 250))
energy_needed=$((daily_contracts * 50000))

trx_for_bandwidth=$((bandwidth_needed / 1000))
trx_for_energy=$((energy_needed / 280))

echo
echo "Resource Requirements:"
echo "  Bandwidth needed: $bandwidth_needed"
echo "  Energy needed: $energy_needed"
echo
echo "TRX to stake:"
echo "  For Bandwidth: $trx_for_bandwidth TRX"
echo "  For Energy: $trx_for_energy TRX"
echo "  Total: $((trx_for_bandwidth + trx_for_energy)) TRX"
echo

read -p "Proceed with staking? (y/n): " confirm

if [ "$confirm" = "y" ]; then
  # Convert to SUN and stake
  stake_trx $((trx_for_bandwidth * 1000000)) "BANDWIDTH"
  sleep 2
  stake_trx $((trx_for_energy * 1000000)) "ENERGY"
fi
```

```javascript
const TronWeb = require('tronweb');

class TronStakingManager {
  constructor(apiKey, privateKey = null) {
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
    this.headers = { 'Content-Type': 'application/json' };
    this.privateKey = privateKey;
    
    // Initialize TronWeb for signing if private key provided
    if (privateKey) {
      this.tronWeb = new TronWeb({
        fullHost: this.apiUrl,
        privateKey: privateKey
      });
    }
  }
  
  // Create freeze balance v2 transaction
  async createFreezeV2Transaction(address, amountTRX, resource = 'ENERGY') {
    const amountSUN = amountTRX * 1_000_000; // Convert TRX to SUN
    
    const response = await fetch(`${this.apiUrl}/wallet/freezebalancev2`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify({
        owner_address: address,
        frozen_balance: amountSUN,
        resource: resource.toUpperCase(),
        visible: true
      })
    });
    
    if (!response.ok) {
      throw new Error(`Freeze transaction failed: ${response.statusText}`);
    }
    
    return await response.json();
  }
  
  // Sign and broadcast transaction
  async stakeAndBroadcast(address, amountTRX, resource = 'ENERGY') {
    if (!this.privateKey) {
      throw new Error('Private key required for signing');
    }
    
    // Create transaction
    const transaction = await this.createFreezeV2Transaction(address, amountTRX, resource);
    
    // Sign transaction
    const signedTx = await this.tronWeb.trx.sign(transaction);
    
    // Broadcast transaction
    const result = await this.broadcastTransaction(signedTx);
    
    return {
      txid: result.txid,
      success: result.result,
      resource: resource,
      amountTRX: amountTRX,
      message: result.message || 'Transaction broadcast successfully'
    };
  }
  
  async broadcastTransaction(signedTransaction) {
    const response = await fetch(`${this.apiUrl}/wallet/broadcasttransaction`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(signedTransaction)
    });
    
    return await response.json();
  }
  
  // Calculate optimal stake amount
  async calculateOptimalStake(address, dailyOperations = 100) {
    // Get current account resources
    const accountResource = await this.getAccountResource(address);
    
    // Estimate required resources
    const bandwidthPerTx = 250; // Average bandwidth per transaction
    const energyPerContract = 50000; // Average energy per contract call
    
    const dailyBandwidth = dailyOperations * bandwidthPerTx;
    const dailyEnergy = dailyOperations * energyPerContract;
    
    // Calculate TRX needed (approximate)
    const trxForBandwidth = Math.ceil(dailyBandwidth / 1000); // ~1000 bandwidth per TRX
    const trxForEnergy = Math.ceil(dailyEnergy / 280); // ~280 energy per TRX
    
    return {
      recommended: {
        bandwidth: trxForBandwidth,
        energy: trxForEnergy
      },
      current: {
        bandwidth: accountResource.freeNetLimit || 0,
        energy: accountResource.EnergyLimit || 0
      },
      dailyRequirement: {
        bandwidth: dailyBandwidth,
        energy: dailyEnergy
      }
    };
  }
  
  async getAccountResource(address) {
    const response = await fetch(`${this.apiUrl}/wallet/getaccountresource`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify({
        address: address,
        visible: true
      })
    });
    
    return await response.json();
  }
  
  // Batch stake for multiple resources
  async stakeForResources(address, bandwidthTRX, energyTRX) {
    const results = [];
    
    if (bandwidthTRX > 0) {
      try {
        const bandwidthResult = await this.stakeAndBroadcast(
          address,
          bandwidthTRX,
          'BANDWIDTH'
        );
        results.push({
          type: 'BANDWIDTH',
          success: true,
          ...bandwidthResult
        });
      } catch (error) {
        results.push({
          type: 'BANDWIDTH',
          success: false,
          error: error.message
        });
      }
    }
    
    if (energyTRX > 0) {
      // Wait 3 seconds between transactions
      await new Promise(resolve => setTimeout(resolve, 3000));
      
      try {
        const energyResult = await this.stakeAndBroadcast(
          address,
          energyTRX,
          'ENERGY'
        );
        results.push({
          type: 'ENERGY',
          success: true,
          ...energyResult
        });
      } catch (error) {
        results.push({
          type: 'ENERGY',
          success: false,
          error: error.message
        });
      }
    }
    
    return results;
  }
  
  // Estimate staking rewards
  estimateStakingRewards(amountTRX, durationDays = 365) {
    const annualAPR = 0.05; // Approximate 5% APR
    const dailyRate = annualAPR / 365;
    const rewards = amountTRX * dailyRate * durationDays;
    
    return {
      amountStaked: amountTRX,
      duration: durationDays,
      estimatedRewards: rewards.toFixed(6),
      apr: (annualAPR * 100).toFixed(2) + '%',
      daily: (amountTRX * dailyRate).toFixed(6),
      monthly: (amountTRX * dailyRate * 30).toFixed(6),
      yearly: (amountTRX * annualAPR).toFixed(6)
    };
  }
}

// Resource Calculator
class ResourceCalculator {
  constructor() {
    this.rates = {
      bandwidth: {
        perTRX: 1000, // Approximate bandwidth per TRX
        perTransaction: 250 // Average bandwidth per transaction
      },
      energy: {
        perTRX: 280, // Approximate energy per TRX
        perContractCall: 50000 // Average energy per smart contract call
      }
    };
  }
  
  calculateRequiredTRX(resourceType, amount) {
    if (resourceType === 'BANDWIDTH') {
      return Math.ceil(amount / this.rates.bandwidth.perTRX);
    } else if (resourceType === 'ENERGY') {
      return Math.ceil(amount / this.rates.energy.perTRX);
    }
    throw new Error('Invalid resource type');
  }
  
  estimateResourcesFromTRX(trxAmount, resourceType) {
    if (resourceType === 'BANDWIDTH') {
      return {
        bandwidth: trxAmount * this.rates.bandwidth.perTRX,
        transactions: Math.floor(
          (trxAmount * this.rates.bandwidth.perTRX) / 
          this.rates.bandwidth.perTransaction
        )
      };
    } else if (resourceType === 'ENERGY') {
      return {
        energy: trxAmount * this.rates.energy.perTRX,
        contractCalls: Math.floor(
          (trxAmount * this.rates.energy.perTRX) / 
          this.rates.energy.perContractCall
        )
      };
    }
    throw new Error('Invalid resource type');
  }
  
  getRecommendation(dailyTransactions, dailyContractCalls) {
    const bandwidthNeeded = dailyTransactions * this.rates.bandwidth.perTransaction;
    const energyNeeded = dailyContractCalls * this.rates.energy.perContractCall;
    
    return {
      bandwidth: {
        required: bandwidthNeeded,
        trxToStake: this.calculateRequiredTRX('BANDWIDTH', bandwidthNeeded),
        dailyTransactions: dailyTransactions
      },
      energy: {
        required: energyNeeded,
        trxToStake: this.calculateRequiredTRX('ENERGY', energyNeeded),
        dailyContractCalls: dailyContractCalls
      },
      total: {
        trxRequired: 
          this.calculateRequiredTRX('BANDWIDTH', bandwidthNeeded) +
          this.calculateRequiredTRX('ENERGY', energyNeeded)
      }
    };
  }
}

// Usage examples
(async () => {
  const staking = new TronStakingManager('YOUR_API_KEY', 'YOUR_PRIVATE_KEY');
  const calculator = new ResourceCalculator();
  
  try {
    // Calculate resources needed
    const recommendation = calculator.getRecommendation(
      100, // Daily transactions
      50   // Daily smart contract calls
    );
    console.log('Resource Recommendation:', recommendation);
    
    // Estimate rewards
    const rewards = staking.estimateStakingRewards(10000, 365);
    console.log('Staking Rewards Estimate:', rewards);
    
    // Calculate optimal stake
    const optimal = await staking.calculateOptimalStake(
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
      100
    );
    console.log('Optimal Stake:', optimal);
    
    // Stake TRX for energy
    const stakeResult = await staking.stakeAndBroadcast(
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
      1000, // 1000 TRX
      'ENERGY'
    );
    console.log('Stake Result:', stakeResult);
    
    // Batch stake for both resources
    const batchResult = await staking.stakeForResources(
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
      500,  // 500 TRX for bandwidth
      1000  // 1000 TRX for energy
    );
    console.log('Batch Stake Results:', batchResult);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import time
from typing import Dict, Optional, List
from datetime import datetime, timedelta

class TronStakingManager:
    def __init__(self, api_key: str, private_key: Optional[str] = None):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {'Content-Type': 'application/json'}
        self.private_key = private_key
    
    def create_freeze_v2_transaction(
        self,
        address: str,
        amount_trx: float,
        resource: str = 'ENERGY'
    ) -> Dict:
        """
        Create a freeze balance v2 transaction
        """
        amount_sun = int(amount_trx * 1_000_000)  # Convert TRX to SUN
        
        url = f"{self.base_url}/wallet/freezebalancev2"
        payload = {
            "owner_address": address,
            "frozen_balance": amount_sun,
            "resource": resource.upper(),
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def stake_trx(
        self,
        address: str,
        amount_trx: float,
        resource: str = 'ENERGY',
        sign_and_broadcast: bool = False
    ) -> Dict:
        """
        Stake TRX for resources
        """
        # Create transaction
        transaction = self.create_freeze_v2_transaction(address, amount_trx, resource)
        
        if sign_and_broadcast and self.private_key:
            # Sign transaction (requires tronpy or similar library)
            # signed_tx = self.sign_transaction(transaction)
            # result = self.broadcast_transaction(signed_tx)
            # return result
            pass
        
        return {
            'transaction': transaction,
            'amount_trx': amount_trx,
            'resource': resource,
            'status': 'created',
            'message': 'Transaction created. Sign and broadcast to complete.'
        }
    
    def calculate_optimal_stake(
        self,
        address: str,
        daily_operations: int = 100
    ) -> Dict:
        """
        Calculate optimal stake amount based on usage
        """
        # Get current resources
        resources = self.get_account_resource(address)
        
        # Estimate requirements
        bandwidth_per_tx = 250
        energy_per_contract = 50000
        
        daily_bandwidth = daily_operations * bandwidth_per_tx
        daily_energy = daily_operations * energy_per_contract
        
        # Calculate TRX needed
        trx_for_bandwidth = daily_bandwidth // 1000  # ~1000 bandwidth per TRX
        trx_for_energy = daily_energy // 280  # ~280 energy per TRX
        
        return {
            'recommended': {
                'bandwidth_trx': trx_for_bandwidth,
                'energy_trx': trx_for_energy,
                'total_trx': trx_for_bandwidth + trx_for_energy
            },
            'current_resources': {
                'bandwidth': resources.get('freeNetLimit', 0),
                'energy': resources.get('EnergyLimit', 0)
            },
            'daily_requirement': {
                'bandwidth': daily_bandwidth,
                'energy': daily_energy,
                'operations': daily_operations
            }
        }
    
    def get_account_resource(self, address: str) -> Dict:
        """
        Get account resource information
        """
        url = f"{self.base_url}/wallet/getaccountresource"
        payload = {
            "address": address,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def batch_stake(
        self,
        address: str,
        bandwidth_trx: float,
        energy_trx: float
    ) -> List[Dict]:
        """
        Stake for multiple resources in batch
        """
        results = []
        
        # Stake for bandwidth
        if bandwidth_trx > 0:
            try:
                bandwidth_result = self.stake_trx(address, bandwidth_trx, 'BANDWIDTH')
                results.append({
                    'type': 'BANDWIDTH',
                    'success': True,
                    **bandwidth_result
                })
            except Exception as e:
                results.append({
                    'type': 'BANDWIDTH',
                    'success': False,
                    'error': str(e)
                })
        
        # Wait between transactions
        time.sleep(3)
        
        # Stake for energy
        if energy_trx > 0:
            try:
                energy_result = self.stake_trx(address, energy_trx, 'ENERGY')
                results.append({
                    'type': 'ENERGY',
                    'success': True,
                    **energy_result
                })
            except Exception as e:
                results.append({
                    'type': 'ENERGY',
                    'success': False,
                    'error': str(e)
                })
        
        return results
    
    def estimate_staking_rewards(
        self,
        amount_trx: float,
        duration_days: int = 365
    ) -> Dict:
        """
        Estimate staking rewards
        """
        annual_apr = 0.05  # Approximate 5% APR
        daily_rate = annual_apr / 365
        
        rewards = amount_trx * daily_rate * duration_days
        
        return {
            'amount_staked': amount_trx,
            'duration_days': duration_days,
            'estimated_rewards': round(rewards, 6),
            'apr': f"{annual_apr * 100:.2f}%",
            'daily_rewards': round(amount_trx * daily_rate, 6),
            'monthly_rewards': round(amount_trx * daily_rate * 30, 6),
            'yearly_rewards': round(amount_trx * annual_apr, 6)
        }

class ResourceCalculator:
    """
    Calculate resource requirements and recommendations
    """
    def __init__(self):
        self.rates = {
            'bandwidth': {
                'per_trx': 1000,  # Bandwidth per TRX
                'per_transaction': 250  # Average bandwidth per tx
            },
            'energy': {
                'per_trx': 280,  # Energy per TRX
                'per_contract_call': 50000  # Average energy per call
            }
        }
    
    def calculate_required_trx(
        self,
        resource_type: str,
        amount: int
    ) -> int:
        """
        Calculate TRX needed for specific resource amount
        """
        resource_type = resource_type.upper()
        
        if resource_type == 'BANDWIDTH':
            return (amount + self.rates['bandwidth']['per_trx'] - 1) // \
                   self.rates['bandwidth']['per_trx']
        elif resource_type == 'ENERGY':
            return (amount + self.rates['energy']['per_trx'] - 1) // \
                   self.rates['energy']['per_trx']
        else:
            raise ValueError(f"Invalid resource type: {resource_type}")
    
    def estimate_resources_from_trx(
        self,
        trx_amount: float,
        resource_type: str
    ) -> Dict:
        """
        Estimate resources obtained from TRX amount
        """
        resource_type = resource_type.upper()
        
        if resource_type == 'BANDWIDTH':
            bandwidth = int(trx_amount * self.rates['bandwidth']['per_trx'])
            return {
                'bandwidth': bandwidth,
                'estimated_transactions': bandwidth // \
                    self.rates['bandwidth']['per_transaction']
            }
        elif resource_type == 'ENERGY':
            energy = int(trx_amount * self.rates['energy']['per_trx'])
            return {
                'energy': energy,
                'estimated_contract_calls': energy // \
                    self.rates['energy']['per_contract_call']
            }
        else:
            raise ValueError(f"Invalid resource type: {resource_type}")
    
    def get_recommendation(
        self,
        daily_transactions: int,
        daily_contract_calls: int
    ) -> Dict:
        """
        Get staking recommendation based on usage
        """
        bandwidth_needed = daily_transactions * \
                          self.rates['bandwidth']['per_transaction']
        energy_needed = daily_contract_calls * \
                       self.rates['energy']['per_contract_call']
        
        bandwidth_trx = self.calculate_required_trx('BANDWIDTH', bandwidth_needed)
        energy_trx = self.calculate_required_trx('ENERGY', energy_needed)
        
        return {
            'bandwidth': {
                'daily_requirement': bandwidth_needed,
                'trx_to_stake': bandwidth_trx,
                'daily_transactions': daily_transactions
            },
            'energy': {
                'daily_requirement': energy_needed,
                'trx_to_stake': energy_trx,
                'daily_contract_calls': daily_contract_calls
            },
            'total': {
                'trx_required': bandwidth_trx + energy_trx,
                'monthly_trx': (bandwidth_trx + energy_trx) * 30,
                'yearly_trx': (bandwidth_trx + energy_trx) * 365
            }
        }

class StakingMonitor:
    """
    Monitor and analyze staking positions
    """
    def __init__(self, api_key: str):
        self.staking = TronStakingManager(api_key)
        self.calculator = ResourceCalculator()
    
    def analyze_account(self, address: str) -> Dict:
        """
        Analyze account staking status
        """
        resources = self.staking.get_account_resource(address)
        
        # Calculate utilization
        bandwidth_used = resources.get('freeNetUsed', 0) + \
                        resources.get('NetUsed', 0)
        bandwidth_limit = resources.get('freeNetLimit', 0) + \
                         resources.get('NetLimit', 0)
        
        energy_used = resources.get('EnergyUsed', 0)
        energy_limit = resources.get('EnergyLimit', 0)
        
        bandwidth_utilization = (bandwidth_used / bandwidth_limit * 100) \
                               if bandwidth_limit > 0 else 0
        energy_utilization = (energy_used / energy_limit * 100) \
                            if energy_limit > 0 else 0
        
        return {
            'address': address,
            'bandwidth': {
                'used': bandwidth_used,
                'limit': bandwidth_limit,
                'available': max(0, bandwidth_limit - bandwidth_used),
                'utilization': f"{bandwidth_utilization:.2f}%"
            },
            'energy': {
                'used': energy_used,
                'limit': energy_limit,
                'available': max(0, energy_limit - energy_used),
                'utilization': f"{energy_utilization:.2f}%"
            },
            'recommendations': self._get_recommendations(
                bandwidth_utilization,
                energy_utilization
            )
        }
    
    def _get_recommendations(
        self,
        bandwidth_util: float,
        energy_util: float
    ) -> List[str]:
        """
        Get staking recommendations based on utilization
        """
        recommendations = []
        
        if bandwidth_util > 80:
            recommendations.append("High bandwidth usage - consider staking more TRX for bandwidth")
        elif bandwidth_util < 20:
            recommendations.append("Low bandwidth usage - you may have excess staked for bandwidth")
        
        if energy_util > 80:
            recommendations.append("High energy usage - consider staking more TRX for energy")
        elif energy_util < 20:
            recommendations.append("Low energy usage - you may have excess staked for energy")
        
        if not recommendations:
            recommendations.append("Resource usage is balanced")
        
        return recommendations

# Usage examples
if __name__ == "__main__":
    # Initialize managers
    staking = TronStakingManager('YOUR_API_KEY')
    calculator = ResourceCalculator()
    monitor = StakingMonitor('YOUR_API_KEY')
    
    try:
        # Get staking recommendation
        recommendation = calculator.get_recommendation(
            daily_transactions=100,
            daily_contract_calls=50
        )
        print("Staking Recommendation:")
        print(json.dumps(recommendation, indent=2))
        
        # Estimate rewards
        rewards = staking.estimate_staking_rewards(
            amount_trx=10000,
            duration_days=365
        )
        print("\nEstimated Rewards:")
        print(json.dumps(rewards, indent=2))
        
        # Calculate optimal stake
        optimal = staking.calculate_optimal_stake(
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            daily_operations=100
        )
        print("\nOptimal Stake:")
        print(json.dumps(optimal, indent=2))
        
        # Analyze account
        analysis = monitor.analyze_account('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN')
        print("\nAccount Analysis:")
        print(json.dumps(analysis, indent=2))
        
        # Create stake transaction
        stake_tx = staking.stake_trx(
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            amount_trx=1000,
            resource='ENERGY'
        )
        print("\nStake Transaction Created:")
        print(json.dumps(stake_tx, indent=2))
        
    except Exception as e:
        print(f"Error: {e}")
```

## Common Use Cases

### 1. Auto-Staking System

```javascript
class AutoStakingSystem {
  constructor(apiKey) {
    this.staking = new TronStakingManager(apiKey);
    this.minBalance = 1000; // Minimum TRX to keep unstaked
  }
  
  async autoStake(address, keepBalance = 1000) {
    // Get current balance
    const account = await this.getAccount(address);
    const availableTRX = (account.balance / 1_000_000) - keepBalance;
    
    if (availableTRX <= 0) {
      return { message: 'Insufficient balance for staking' };
    }
    
    // Split 30% bandwidth, 70% energy (typical DApp usage)
    const bandwidthTRX = Math.floor(availableTRX * 0.3);
    const energyTRX = Math.floor(availableTRX * 0.7);
    
    return await this.staking.stakeForResources(
      address,
      bandwidthTRX,
      energyTRX
    );
  }
}
```

### 2. Resource Optimization

```javascript
async function optimizeResources(address) {
  const resources = await getAccountResource(address);
  
  // Check utilization
  const bandwidthUtil = resources.freeNetUsed / resources.freeNetLimit;
  const energyUtil = resources.EnergyUsed / resources.EnergyLimit;
  
  const recommendations = [];
  
  if (bandwidthUtil > 0.8) {
    recommendations.push({
      action: 'STAKE',
      resource: 'BANDWIDTH',
      reason: 'High bandwidth utilization',
      suggestedTRX: 1000
    });
  }
  
  if (energyUtil > 0.8) {
    recommendations.push({
      action: 'STAKE',
      resource: 'ENERGY',
      reason: 'High energy utilization',
      suggestedTRX: 5000
    });
  }
  
  return recommendations;
}
```

### 3. Staking Pool Management

```javascript
class StakingPool {
  async distributeStakes(participants, totalTRX) {
    const stakes = [];
    
    for (const participant of participants) {
      const share = (participant.contribution / 100) * totalTRX;
      
      stakes.push({
        address: participant.address,
        amount: share,
        resource: participant.preferredResource || 'ENERGY'
      });
    }
    
    return this.executeStakes(stakes);
  }
}
```

## Resource Calculation

| Resource     | Rate            | Usage                |
| ------------ | --------------- | -------------------- |
| Bandwidth    | \~1,000 per TRX | Regular transactions |
| Energy       | \~280 per TRX   | Smart contract calls |
| Voting Power | 1 vote per TRX  | SR voting            |

### Staking Recommendations by Use Case

| Use Case       | Bandwidth (TRX) | Energy (TRX) | Total  |
| -------------- | --------------- | ------------ | ------ |
| Basic Wallet   | 100             | 0            | 100    |
| DeFi User      | 500             | 5,000        | 5,500  |
| DApp Developer | 1,000           | 20,000       | 21,000 |
| Exchange       | 10,000          | 50,000       | 60,000 |

## Best Practices

1. **Keep Reserve** - Always keep 50-100 TRX unstaked for fees
2. **Balance Resources** - Monitor usage and adjust stakes accordingly
3. **Batch Operations** - Stake for both resources in one session
4. **Monitor Rewards** - Track staking rewards and compound regularly
5. **Plan Unstaking** - Remember 14-day waiting period for unstaking

## Notes

- **Lock Period**: Staked TRX has a minimum 14-day lock period
- **Rewards**: Staking rewards are distributed every 6 hours
- **Voting Power**: Staked TRX provides voting power for Super Representatives
- **Resource Recovery**: Bandwidth recovers 24 hours, energy recovers based on consumption

## Related Methods

- [wallet/unfreezebalancev2](https://www.dwellir.com/docs/tron/wallet-unfreezebalancev2) - Unstake TRX
- [wallet/delegateresource](https://www.dwellir.com/docs/tron/wallet-delegateresource) - Delegate resources
- [wallet/getaccountresource](https://www.dwellir.com/docs/tron/wallet-getaccountresource) - Check resources

***

*Need help? Contact [support](mailto:support@dwellir.com) or visit our [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/getaccount - Get TRON Account Information

# wallet/getaccount - Get TRON Account Information

**Dwellir's TRON endpoints** deliver account information in under 50ms with 99.9% uptime.
Get comprehensive account data including balance, resources, and token holdings instantly.

[Start building with free API access](https://dashboard.dwellir.com/register)

Get comprehensive information about a TRON account including TRX balance, bandwidth, energy, TRC20 tokens, and account permissions.

## When to Use This Method

`wallet/getaccount` is essential for:

- **Balance Checks** - Display TRX balance in wallets and apps
- **Resource Monitoring** - Track bandwidth and energy consumption
- **Token Holdings** - View all TRC20/TRC721 tokens owned
- **Account Validation** - Verify account exists and activation status
- **Permission Analysis** - Check multi-signature and account permissions

## Request Parameters

- `address` (`string, required`): TRON address in Base58 format (starts with 'T') Example: `"TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF"`
- `visible` (`boolean, optional`): `true` - Use Base58 address format `false` - Use hex address format

## Request Example

```json
{
  "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
  "visible": true
}
```

## Response Fields

- `address` (`string, required`): Account address in the format requested by the `visible` flag.
- `balance` (`integer, optional`): TRX balance in SUN. Divide by 1,000,000 to display TRX.
- `create_time` (`integer, optional`): Unix timestamp in milliseconds for when the account was created.
- `latest_opration_time` (`integer, optional`): Unix timestamp in milliseconds for the latest account operation. TRON returns the field with this spelling.
- `account_resource` (`object, optional`): Energy usage and delegated resource information for the account.
- `owner_permission` (`object, optional`): Owner permission threshold and signer set for the account.
- `active_permission` (`array, optional`): Active permission entries for operational policies such as multisig roles.
- `assetV2` (`array, optional`): TRC10 and token-balance style holdings exposed by the node for this account.

## Successful Response

```json
{
  "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
  "balance": 71052023249,
  "create_time": 1698225282000,
  "latest_opration_time": 1773858180000,
  "account_resource": {
    "energy_usage": 62965042,
    "latest_consume_time_for_energy": 1773852507000
  },
  "owner_permission": {
    "permission_name": "owner",
    "threshold": 1
  },
  "active_permission": [
    {
      "type": "Active",
      "id": 2,
      "permission_name": "active",
      "threshold": 1
    }
  ]
}
```

## Error Responses

### Error 1

- Description: Malformed TRON address

### Error 2

- Description: RPC connection failed

### Error 3

- Description: Account doesn't exist

## Implementation Examples

cURL
JavaScript
Python

```bash
# Basic account query
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccount" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }'

# Query with hex address format
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccount" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "41E552F6487585C2B58BC2C9BB4492BC1F17132CD0",
    "visible": false
  }'

# Using jq to parse response
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccount" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }' | jq '{
    address: .address,
    balance_trx: (.balance // 0) / 1000000,
    balance_sun: .balance // 0,
    free_bandwidth: .free_net_limit // 0,
    used_bandwidth: .free_net_used // 0
  }'
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get account information
async function getAccount(address) {
  const response = await fetch(`${TRON_API}/wallet/getaccount`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      address: address,
      visible: true
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  return await response.json();
}

// Enhanced account info with formatted data
async function getAccountInfo(address) {
  try {
    const account = await getAccount(address);
    
    // Check if account exists
    if (!account.address) {
      return {
        exists: false,
        message: 'Account not found or not activated'
      };
    }
    
    return {
      exists: true,
      address: account.address,
      balance: {
        trx: (account.balance || 0) / 1_000_000, // Convert SUN to TRX
        sun: account.balance || 0
      },
      resources: {
        bandwidth: account.net_limit || 0,
        energy: account.energy_limit || 0,
        freeNetUsed: account.free_net_used || 0,
        freeNetLimit: account.free_net_limit || 0
      },
      tokens: account.assetV2 || [],
      permissions: {
        owner: account.owner_permission,
        active: account.active_permission
      },
      timestamps: {
        created: account.create_time,
      lastActive: account.latest_opration_time
      }
    };
  } catch (error) {
    console.error('Error fetching account:', error);
    throw error;
  }
}

// Check multiple accounts
async function checkMultipleAccounts(addresses) {
  const results = await Promise.allSettled(
    addresses.map(addr => getAccountInfo(addr))
  );
  
  return results.map((result, index) => ({
    address: addresses[index],
    success: result.status === 'fulfilled',
    data: result.status === 'fulfilled' ? result.value : null,
    error: result.status === 'rejected' ? result.reason.message : null
  }));
}

// Usage examples
(async () => {
  try {
    // Single account query
    const account = await getAccountInfo('TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF');
    console.log('Account balance:', account.balance.trx, 'TRX');
    
    // Multiple accounts
    const addresses = [
      'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF',
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh'
    ];
    const results = await checkMultipleAccounts(addresses);
    console.log('Multiple accounts:', results);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
from typing import Dict, List, Optional

class TronAccountClient:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def get_account(self, address: str, visible: bool = True) -> Dict:
        """Get raw account information from TRON network"""
        url = f"{self.base_url}/wallet/getaccount"
        
        payload = {
            "address": address,
            "visible": visible
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def get_account_info(self, address: str) -> Dict:
        """Get formatted account information"""
        try:
            account = self.get_account(address)
            
            # Check if account exists
            if not account.get('address'):
                return {
                    'exists': False,
                    'message': 'Account not found or not activated'
                }
            
            return {
                'exists': True,
                'address': account['address'],
                'balance': {
                    'trx': (account.get('balance', 0)) / 1_000_000,  # Convert SUN to TRX
                    'sun': account.get('balance', 0)
                },
                'resources': {
                    'bandwidth': account.get('net_limit', 0),
                    'energy': account.get('energy_limit', 0),
                    'free_net_used': account.get('free_net_used', 0),
                    'free_net_limit': account.get('free_net_limit', 0)
                },
                'tokens': account.get('assetV2', []),
                'permissions': {
                    'owner': account.get('owner_permission'),
                    'active': account.get('active_permission')
                },
                'timestamps': {
                    'created': account.get('create_time'),
                    'last_active': account.get('latest_opration_time')
                }
            }
        except requests.RequestException as e:
            print(f"Error fetching account: {e}")
            raise
    
    def check_multiple_accounts(self, addresses: List[str]) -> List[Dict]:
        """Check multiple accounts efficiently"""
        results = []
        
        for address in addresses:
            try:
                account_info = self.get_account_info(address)
                results.append({
                    'address': address,
                    'success': True,
                    'data': account_info,
                    'error': None
                })
            except Exception as e:
                results.append({
                    'address': address,
                    'success': False,
                    'data': None,
                    'error': str(e)
                })
        
        return results
    
    def get_balance_in_trx(self, address: str) -> float:
        """Get account balance in TRX (simplified)"""
        account = self.get_account(address)
        return (account.get('balance', 0)) / 1_000_000

# Usage examples
if __name__ == "__main__":
    client = TronAccountClient('YOUR_API_KEY')
    
    try:
        # Single account query
        account = client.get_account_info('TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF')
        print(f"Account balance: {account['balance']['trx']} TRX")
        
        # Multiple accounts
        addresses = [
            'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF',
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh'
        ]
        results = client.check_multiple_accounts(addresses)
        
        for result in results:
            if result['success']:
                print(f"{result['address']}: {result['data']['balance']['trx']} TRX")
            else:
                print(f"{result['address']}: Error - {result['error']}")
                
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful Response (Active Account)

```json
{
  "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
  "balance": 1500000000,
  "create_time": 1547736132000,
  "latest_opration_time": 1734567890000,
  "free_net_usage": 0,
  "free_net_limit": 5000,
  "net_limit": 10000,
  "net_usage": 1234,
  "energy_limit": 50000,
  "energy_usage": 5000,
  "assetV2": [
    {
      "key": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
      "value": 100000000
    }
  ],
  "owner_permission": {
    "type": 0,
    "id": 0,
    "permission_name": "owner",
    "threshold": 1,
    "keys": [
      {
        "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
        "weight": 1
      }
    ]
  },
  "active_permission": [
    {
      "type": 2,
      "id": 2,
      "permission_name": "active0",
      "threshold": 1,
      "operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
      "keys": [
        {
          "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
          "weight": 1
        }
      ]
    }
  ]
}
```

### Empty Response (Non-existent Account)

```json
{}
```

## Common Use Cases

### 1. Wallet Balance Display

```javascript
async function getWalletBalance(address) {
  const account = await getAccountInfo(address);
  
  if (!account.exists) {
    return {
      status: 'inactive',
      balance: 0,
      message: 'Account not activated. Send TRX to activate.'
    };
  }
  
  return {
    status: 'active',
    balance: account.balance.trx,
    freeTransactions: account.resources.freeNetLimit - account.resources.freeNetUsed,
    lastActive: new Date(account.timestamps.lastActive).toLocaleString()
  };
}
```

### 2. Account Validation

```javascript
async function validateTronAddress(address) {
  // Basic format validation
  if (!address.startsWith('T') || address.length !== 34) {
    return { valid: false, reason: 'Invalid address format' };
  }
  
  try {
    const account = await getAccount(address);
    return {
      valid: true,
      exists: !!account.address,
      activated: !!account.balance || account.balance === 0
    };
  } catch (error) {
    return { valid: false, reason: 'Address lookup failed' };
  }
}
```

### 3. Resource Monitoring Dashboard

```javascript
async function getResourceStatus(address) {
  const account = await getAccountInfo(address);
  
  if (!account.exists) {
    return { error: 'Account not found' };
  }
  
  const bandwidthUsage = (account.resources.freeNetUsed / account.resources.freeNetLimit) * 100;
  const energyUsage = account.resources.energy > 0 
    ? (account.resources.energyUsed / account.resources.energy) * 100 
    : 0;
  
  return {
    bandwidth: {
      used: account.resources.freeNetUsed,
      limit: account.resources.freeNetLimit,
      usage_percent: bandwidthUsage.toFixed(2),
      status: bandwidthUsage > 80 ? 'high' : bandwidthUsage > 50 ? 'medium' : 'low'
    },
    energy: {
      used: account.resources.energyUsed || 0,
      limit: account.resources.energy,
      usage_percent: energyUsage.toFixed(2),
      status: energyUsage > 80 ? 'high' : energyUsage > 50 ? 'medium' : 'low'
    },
    recommendations: generateResourceRecommendations(bandwidthUsage, energyUsage)
  };
}

function generateResourceRecommendations(bandwidthUsage, energyUsage) {
  const recommendations = [];
  
  if (bandwidthUsage > 80) {
    recommendations.push('Consider freezing TRX for bandwidth');
  }
  
  if (energyUsage > 80) {
    recommendations.push('Freeze TRX for energy or rent energy');
  }
  
  if (bandwidthUsage < 20 && energyUsage < 20) {
    recommendations.push('Resources are well managed');
  }
  
  return recommendations;
}
```

### 4. Multi-Signature Account Analysis

```javascript
async function analyzeAccountPermissions(address) {
  const account = await getAccount(address);
  
  if (!account.address) {
    return { error: 'Account not found' };
  }
  
  const isMultiSig = account.owner_permission?.threshold > 1 || 
                     account.active_permission?.some(p => p.threshold > 1);
  
  return {
    address: account.address,
    isMultiSignature: isMultiSig,
    ownerPermission: {
      threshold: account.owner_permission?.threshold || 1,
      keyCount: account.owner_permission?.keys?.length || 1
    },
    activePermissions: account.active_permission?.map(p => ({
      id: p.id,
      name: p.permission_name,
      threshold: p.threshold,
      keyCount: p.keys?.length || 0
    })) || []
  };
}
```

## Performance Tips

1. **Batch Requests** - Query multiple accounts concurrently but respect rate limits
2. **Cache Results** - Cache account data for 30-60 seconds to reduce API calls
3. **Selective Queries** - Only fetch account data when needed, not on every page load
4. **Error Boundaries** - Implement proper error handling for non-existent accounts

```javascript
// Simple caching example
class AccountCache {
  constructor(ttl = 60000) { // 1 minute TTL
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  async get(address) {
    const cached = this.cache.get(address);
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }
    
    const account = await getAccountInfo(address);
    this.cache.set(address, {
      data: account,
      timestamp: Date.now()
    });
    
    return account;
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/getaccountbalance - Get TRON Account Bal...

# wallet/getaccountbalance - Get TRON Account Bal...

Retrieve the native TRX balance of a TRON account at a specific block height. This endpoint returns TRX balance only — it does not return TRC-10 or TRC-20 token balances.

## Use Cases

`wallet/getaccountbalance` is useful for:

- **Wallet Applications** - Display TRX balance at a given block height
- **Payment Verification** - Confirm TRX payment receipt at a specific block

## For Token Balances

This endpoint does **not** return token balances. Use the following approaches instead:

| Goal                      | Endpoint / Approach                                                                                |
| ------------------------- | -------------------------------------------------------------------------------------------------- |
| Current TRX balance       | [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount)                                                  |
| Current TRC-20 balance    | `wallet/triggerconstantcontract` calling `balanceOf(address)` on the token contract                |
| Historical TRX balance    | `wallet/getaccountbalance`                                                                         |
| Historical TRC-20 balance | Not natively supported by TRON full nodes; use indexed services (TronScan API, Bitquery, Covalent) |

## Request Parameters

- `account_identifier` (`object, required`): Account identification object
- `account_identifier.address` (`string, required`): TRON address (Base58 or Hex)
- `block_identifier` (`object, optional`): Specific block for balance query
- `block_identifier.hash` (`string, optional`): Block hash
- `block_identifier.number` (`number, optional`): Block height
- `visible` (`boolean, optional`): Use Base58 format (default: true)

## Request Example

```json
{
  "account_identifier": {
    "address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
  },
  "block_identifier": {
    "number": 58234567
  },
  "visible": true
}
```

## Response Fields

- `balance` (`number, required`): TRX balance in SUN (1 TRX = 1,000,000 SUN)
- `block_identifier` (`object, required`): Block at which balance was calculated
- `block_identifier.hash` (`string, required`): Block hash
- `block_identifier.number` (`number, required`): Block height

## Successful Response

```json
{
  "balance": 1453878299614,
  "block_identifier": {
    "hash": "0000000004dd7431...",
    "number": 81622065
  }
}
```

## Error Responses

### Error 1

- Code: `400`
- Description: Invalid address format

### Error 2

- Code: `404`
- Description: Block not found

### Error 3

- Code: `429`
- Description: Rate limit exceeded

### Error 4

- Code: `500`
- Description: Internal server error

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get account balance at current block
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountbalance" \
  -H "Content-Type: application/json" \
  -d '{
    "account_identifier": {
      "address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
    },
    "visible": true
  }'

# Get balance at specific block height
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountbalance" \
  -H "Content-Type: application/json" \
  -d '{
    "account_identifier": {
      "address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
    },
    "block_identifier": {
      "number": 81622065
    },
    "visible": true
  }'

# Get balance with hex address format
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountbalance" \
  -H "Content-Type: application/json" \
  -d '{
    "account_identifier": {
      "address": "41E552F6487585C2B58BC2C9BB4492BC1F17132CD0"
    },
    "visible": false
  }'

# Parse balance with jq (balance is in SUN; divide by 1,000,000 for TRX)
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountbalance" \
  -H "Content-Type: application/json" \
  -d '{
    "account_identifier": {
      "address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
    },
    "visible": true
  }' | jq '{
    trx_balance: (.balance // 0) / 1000000,
    sun_balance: .balance // 0,
    block_height: .block_identifier.number,
    block_hash: .block_identifier.hash
  }'
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get current TRX balance
async function getAccountBalance(address) {
  const response = await fetch(`${TRON_API}/wallet/getaccountbalance`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      account_identifier: {
        address: address
      },
      visible: true
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  return await response.json();
}

// Get TRX balance at specific block
async function getBalanceAtBlock(address, blockNumber) {
  const response = await fetch(`${TRON_API}/wallet/getaccountbalance`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      account_identifier: {
        address: address
      },
      block_identifier: {
        number: blockNumber
      },
      visible: true
    })
  });
  
  return await response.json();
}

// Usage example
(async () => {
  try {
    const balance = await getAccountBalance('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN');
    // balance is in SUN — divide by 1,000,000 for TRX
    const trx = balance.balance / 1_000_000;
    console.log(`Balance: ${trx} TRX at block ${balance.block_identifier.number}`);

    // Compare balances at different block heights
    const blocks = [81622063, 81622064, 81622065];
    for (const block of blocks) {
      const result = await getBalanceAtBlock('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN', block);
      console.log(`Block ${block}: ${result.balance / 1_000_000} TRX`);
    }
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
from typing import Dict, List, Optional

class TronBalanceClient:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {'Content-Type': 'application/json'}
    
    def get_account_balance(
        self, 
        address: str, 
        block_number: Optional[int] = None,
        block_hash: Optional[str] = None,
        visible: bool = True
    ) -> Dict:
        """Get TRX balance at current or specific block."""
        url = f"{self.base_url}/wallet/getaccountbalance"
        
        payload = {
            "account_identifier": {
                "address": address
            },
            "visible": visible
        }
        
        if block_number or block_hash:
            payload["block_identifier"] = {}
            if block_number:
                payload["block_identifier"]["number"] = block_number
            if block_hash:
                payload["block_identifier"]["hash"] = block_hash
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def get_trx_balance(self, address: str) -> Dict:
        """Get formatted TRX balance (balance is in SUN)."""
        data = self.get_account_balance(address)
        sun = data.get('balance', 0)
        return {
            'address': address,
            'trx': sun / 1_000_000,
            'sun': sun,
            'block_height': data.get('block_identifier', {}).get('number'),
            'block_hash': data.get('block_identifier', {}).get('hash'),
        }
    
    def get_balance_history(
        self, 
        address: str, 
        block_numbers: List[int]
    ) -> List[Dict]:
        """Get TRX balance at multiple block heights."""
        history = []
        for block_num in block_numbers:
            try:
                balance = self.get_account_balance(
                    address=address,
                    block_number=block_num
                )
                history.append({
                    'block': block_num,
                    'trx': balance.get('balance', 0) / 1_000_000,
                    'sun': balance.get('balance', 0),
                })
            except Exception as e:
                history.append({
                    'block': block_num,
                    'error': str(e)
                })
        return history

# Usage example
if __name__ == "__main__":
    client = TronBalanceClient('YOUR_API_KEY')
    
    try:
        # Get current TRX balance
        balance = client.get_trx_balance('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN')
        print(f"Balance: {balance['trx']} TRX at block {balance['block_height']}")
        
        # Get balance at specific block
        historical = client.get_account_balance(
            address='TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            block_number=81622065
        )
        print(f"Balance at block 81622065: {historical['balance'] / 1_000_000} TRX")
        
        # Get balance history
        history = client.get_balance_history(
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
            [81622063, 81622064, 81622065]
        )
        for entry in history:
            print(f"Block {entry['block']}: {entry.get('trx', 'Error')} TRX")
            
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful Response

```json
{
  "balance": 1453878299614,
  "block_identifier": {
    "hash": "0000000004dd7431...",
    "number": 81622065
  }
}
```

### Zero Balance Response

```json
{
  "balance": 0,
  "block_identifier": {
    "hash": "0000000004dd7431...",
    "number": 81622065
  }
}
```

## Common Use Cases

### 1. TRX Balance Display

```javascript
async function displayBalance(address) {
  const result = await getAccountBalance(address);
  // Balance is in SUN (1 TRX = 1,000,000 SUN)
  const trx = result.balance / 1_000_000;
  
  return {
    display: `${trx.toFixed(6)} TRX`,
    blockHeight: result.block_identifier.number,
  };
}
```

### 2. Payment Confirmation

```javascript
async function confirmPayment(address, expectedAmount, minConfirmations = 19) {
  const balance = await getAccountBalance(address);
  const currentBlock = balance.block_identifier.number;
  
  // Check if payment received (expectedAmount in SUN)
  const received = balance.balance >= expectedAmount;
  
  // Get latest block to check confirmations
  const latestBlock = await getLatestBlock();
  const confirmations = latestBlock.number - currentBlock;
  
  return {
    received,
    balanceSun: balance.balance,
    balanceTrx: balance.balance / 1_000_000,
    confirmations,
    confirmed: received && confirmations >= minConfirmations
  };
}
```

### 3. Balance Change Detection

```javascript
class BalanceMonitor {
  constructor(apiKey, address) {
    this.apiKey = apiKey;
    this.address = address;
    this.lastBalance = null;
  }
  
  async checkForChanges() {
    const current = await getAccountBalance(this.address);
    
    if (this.lastBalance === null) {
      this.lastBalance = current.balance;
      return { changed: false, balanceSun: current.balance };
    }
    
    const changed = current.balance !== this.lastBalance;
    const difference = current.balance - this.lastBalance;
    
    this.lastBalance = current.balance;
    
    return {
      changed,
      balanceSun: current.balance,
      differenceSun: difference,
      differenceTrx: Math.abs(difference) / 1_000_000,
      direction: difference > 0 ? 'received' : 'sent',
    };
  }
}
```

## Best Practices

1. **Cache Results** - Balance queries can be cached for 3 seconds
2. **Batch Requests** - Query multiple accounts in parallel
3. **Monitor Changes** - Use block height to detect balance changes
4. **Validate Addresses** - Check address format before querying

## Related Methods

- [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount) - Get detailed account information (including current TRX balance)
- [wallet/getaccountresource](https://www.dwellir.com/docs/tron/wallet-getaccountresource) - Get resource details
- [wallet/validateaddress](https://www.dwellir.com/docs/tron/wallet-validateaddress) - Validate address format
- [wallet/getaccountnet](https://www.dwellir.com/docs/tron/wallet-getaccountnet) - Get bandwidth usage

***

*Need help? Contact [support](mailto:support@dwellir.com) or check our [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/getaccountnet - Get Account Bandwidth Info

# wallet/getaccountnet - Get Account Bandwidth Info

Get detailed bandwidth (network) resource information for an account.

## Endpoint

```
POST /wallet/getaccountnet
```

## Request Parameters

- `address` (`string, required`): Required parameter: Account address (base58 or hex)
- `visible` (`boolean, required`): Optional parameter: Return base58 addresses (default: false returns hex)

## Request Example

```bash
# Get bandwidth info with base58 address
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountnet \
      -H "Content-Type: application/json" \
      -d '{
        "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
        "visible": true
      }'

    # Get bandwidth info with hex address
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountnet \
      -H "Content-Type: application/json" \
      -d '{
        "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF"
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `freeNetUsed` - Free bandwidth used today `freeNetLimit` - Total free bandwidth available (600 default) `NetUsed` - Staked bandwidth used `NetLimit` - Total staked bandwidth available `TotalNetLimit` - Combined total bandwidth limit `TotalNetWeight` - Total network bandwidth weight `assetNetUsed` - Map of TRC10 token bandwidth usage `assetNetLimit` - Map of TRC10 token bandwidth limits

## Successful Response

```json
{
    "freeNetLimit": 600,
    "NetUsed": 10233992,
    "NetLimit": 157582708,
    "assetNetUsed": [
        {
            "key": "1004977",
            "value": 0
        },
        ...
    ],
    "assetNetLimit": [
        {
            "key": "1004977",
            "value": 1
        },
        {
            "key": "1004920",
            "value": 1
        },
        ...
    ],
    "TotalNetLimit": 43200000000,
    "TotalNetWeight": 26603102669
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get bandwidth info with base58 address
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountnet \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }'

# Get bandwidth info with hex address
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountnet \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF"
  }'
```

```javascript
// Get account bandwidth information
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountnet', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    address: 'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF',
    visible: true
  }),
});

const data = await response.json();

// Calculate bandwidth usage
const freeUsagePercent = (data.freeNetUsed / data.freeNetLimit) * 100;
const stakedUsagePercent = data.NetLimit > 0 ? (data.NetUsed / data.NetLimit) * 100 : 0;

console.log('Bandwidth Information:');
console.log(`Free Bandwidth: ${data.freeNetUsed}/${data.freeNetLimit} (${freeUsagePercent.toFixed(1)}%)`);
console.log(`Staked Bandwidth: ${data.NetUsed}/${data.NetLimit} (${stakedUsagePercent.toFixed(1)}%)`);

// Check if needs more bandwidth
const remainingFree = data.freeNetLimit - data.freeNetUsed;
const remainingStaked = data.NetLimit - data.NetUsed;
const totalRemaining = remainingFree + remainingStaked;

if (totalRemaining < 100) {
  console.log('Warning: Low bandwidth! Consider staking more TRX.');
}
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountnet"

payload = {
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": True
}

response = requests.post(url, json=payload)
data = response.json()

# Display bandwidth information
print("=== Bandwidth Information ===")
print(f"Free Bandwidth: {data.get('freeNetUsed', 0)}/{data.get('freeNetLimit', 0)}")
print(f"Staked Bandwidth: {data.get('NetUsed', 0)}/{data.get('NetLimit', 0)}")

# Calculate usage percentages
free_limit = data.get('freeNetLimit', 1)
staked_limit = data.get('NetLimit', 0)

free_usage = (data.get('freeNetUsed', 0) / free_limit * 100) if free_limit > 0 else 0
staked_usage = (data.get('NetUsed', 0) / staked_limit * 100) if staked_limit > 0 else 0

print(f"\nUsage Rates:")
print(f"  Free: {free_usage:.1f}%")
print(f"  Staked: {staked_usage:.1f}%")

# Check TRC10 token bandwidth
asset_net = data.get('assetNetUsed', {})
if asset_net:
    print("\nTRC10 Token Bandwidth:")
    for token_id, used in asset_net.items():
        limit = data.get('assetNetLimit', {}).get(token_id, 0)
        print(f"  Token {token_id}: {used}/{limit}")
```

## Bandwidth Calculation

```javascript
// Calculate bandwidth costs for transactions
function calculateBandwidthNeeded(transactionSize) {
  // Basic transaction is ~200 bytes
  // Smart contract calls can be 300-500 bytes
  return transactionSize;
}

// Calculate TRX needed for bandwidth
function calculateTRXForBandwidth(bandwidthNeeded) {
  // 1 TRX = 1 bandwidth point when staked
  return bandwidthNeeded;
}

// Example: Check if account has enough bandwidth
async function checkBandwidth(address, transactionSize) {
  const response = await fetch(`${API_URL}/wallet/getaccountnet`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ address, visible: true })
  });
  
  const data = await response.json();
  
  const availableFree = data.freeNetLimit - data.freeNetUsed;
  const availableStaked = data.NetLimit - data.NetUsed;
  const totalAvailable = availableFree + availableStaked;
  
  return {
    hasEnough: totalAvailable >= transactionSize,
    available: totalAvailable,
    needed: transactionSize,
    deficit: Math.max(0, transactionSize - totalAvailable)
  };
}
```

## Bandwidth Management

### Daily Reset

- Free bandwidth resets daily at 00:00 UTC
- Staked bandwidth usage resets daily
- TRC10 token bandwidth resets based on token settings

### Priority Order

1. **TRC10 Token Bandwidth**: Used first for token transfers
2. **Free Bandwidth**: 600 points daily for all accounts
3. **Staked Bandwidth**: From frozen TRX
4. **TRX Burning**: If no bandwidth available, burns TRX

### Bandwidth Consumption

| Operation           | Typical Bandwidth         |
| ------------------- | ------------------------- |
| TRX Transfer        | \~250 points              |
| TRC10 Transfer      | \~300 points              |
| Smart Contract Call | 350-500 points            |
| Account Creation    | \~1000 points             |
| Multi-signature     | +100 points per signature |

## Best Practices

### 1. **Monitor Usage**

```javascript
// Check bandwidth before transactions
const bandwidth = await getAccountNet(address);
if (bandwidth.freeNetUsed > 500) {
  console.warn('Consider staking TRX for more bandwidth');
}
```

### 2. **Optimize Transactions**

- Batch operations when possible
- Minimize transaction data size
- Use efficient contract calls

### 3. **Resource Planning**

- Keep buffer of 100+ bandwidth points
- Stake TRX if doing frequent transactions
- Monitor daily reset timing

## Use Cases

- **Resource Monitoring**: Track bandwidth consumption
- **Transaction Planning**: Ensure sufficient bandwidth before sending
- **Cost Optimization**: Decide between using free/staked bandwidth or burning TRX
- **DApp Integration**: Check user bandwidth before operations
- **Alert Systems**: Notify when bandwidth is low

## Related Methods

- [wallet/getaccountresource](https://www.dwellir.com/docs/tron/wallet-getaccountresource) - Get complete resource info
- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Stake TRX for bandwidth
- [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount) - Get account details

---

## wallet/getaccountresource - Get TRON Account Re...

# wallet/getaccountresource - Get TRON Account Re...

**Dwellir's TRON endpoints** help you monitor and optimize bandwidth/energy usage for zero-fee transactions.
Track resources in real-time to minimize transaction costs on TRON.

[Monitor your resources](https://dashboard.dwellir.com/register)

Retrieves detailed information about an account's bandwidth and energy resources on the TRON network. Essential for managing transaction costs and optimizing resource usage.

## When to Use This Method

`wallet/getaccountresource` is essential for:

- **Resource Monitoring** - Track bandwidth and energy consumption
- **Fee Optimization** - Determine if transactions will be free or require TRX
- **Staking Strategy** - Plan TRX staking for bandwidth/energy
- **Transaction Planning** - Estimate resource requirements
- **Wallet Management** - Display resource status to users

## Request Parameters

- `address` (`string, required`): TRON address in Base58 format Example: `"TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF"`
- `visible` (`boolean, optional`): `true` - Use Base58 address format `false` - Use hex address format

## Request Example

```json
{
  "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
  "visible": true
}
```

## Response Fields

- `result` (`OBJECT, required`): `freeNetLimit` - Daily free bandwidth limit (5000 for new accounts) `freeNetUsed` - Free bandwidth consumed today `NetLimit` - Additional bandwidth from frozen TRX `NetUsed` - Additional bandwidth consumed `EnergyLimit` - Energy from frozen TRX `EnergyUsed` - Energy consumed `tronPowerLimit` - Voting power from staked TRX `assetNetLimit` - Token-specific bandwidth limits `assetNetUsed` - Token-specific bandwidth usage

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get account resources
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountresource" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }'

# Format and analyze resource data
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountresource" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }' | jq '{
    address: "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    bandwidth: {
      free_limit: .freeNetLimit // 0,
      free_used: .freeNetUsed // 0,
      free_remaining: (.freeNetLimit // 0) - (.freeNetUsed // 0),
      staked_limit: .NetLimit // 0,
      staked_used: .NetUsed // 0,
      staked_remaining: (.NetLimit // 0) - (.NetUsed // 0),
      total_remaining: ((.freeNetLimit // 0) - (.freeNetUsed // 0)) + ((.NetLimit // 0) - (.NetUsed // 0))
    },
    energy: {
      limit: .EnergyLimit // 0,
      used: .EnergyUsed // 0,
      remaining: (.EnergyLimit // 0) - (.EnergyUsed // 0)
    },
    voting_power: .tronPowerLimit // 0
  }'

# Resource monitoring script
#!/bin/bash
API_KEY="YOUR_API_KEY"
ADDRESSES=("TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF" "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh")
ALERT_LOG="/tmp/tron_alerts.log"

# Function to get resources for an address
get_resources() {
  local address=$1
  
  curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/getaccountresource" \
    -H "Content-Type: application/json" \
    -d "{\"address\": \"$address\", \"visible\": true}"
}

# Function to analyze resources and generate alerts
analyze_resources() {
  local address=$1
  local resource_data=$2
  
  # Extract resource values
  local free_limit=$(echo "$resource_data" | jq -r '.freeNetLimit // 0')
  local free_used=$(echo "$resource_data" | jq -r '.freeNetUsed // 0')
  local staked_limit=$(echo "$resource_data" | jq -r '.NetLimit // 0')
  local staked_used=$(echo "$resource_data" | jq -r '.NetUsed // 0')
  local energy_limit=$(echo "$resource_data" | jq -r '.EnergyLimit // 0')
  local energy_used=$(echo "$resource_data" | jq -r '.EnergyUsed // 0')
  
  # Calculate remaining resources
  local free_remaining=$((free_limit - free_used))
  local staked_remaining=$((staked_limit - staked_used))
  local total_bandwidth_remaining=$((free_remaining + staked_remaining))
  local energy_remaining=$((energy_limit - energy_used))
  
  # Generate status report
  echo "=== Resource Status for $address ==="
  echo "Bandwidth:"
  echo "  Free: $free_remaining / $free_limit"
  echo "  Staked: $staked_remaining / $staked_limit" 
  echo "  Total: $total_bandwidth_remaining"
  echo "Energy:"
  echo "  Remaining: $energy_remaining / $energy_limit"
  echo ""
  
  # Check for alerts
  local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
  
  if [ "$total_bandwidth_remaining" -lt 500 ]; then
    echo "⚠️  WARNING: Low bandwidth ($total_bandwidth_remaining remaining) - $address" | tee -a "$ALERT_LOG"
  fi
  
  if [ "$total_bandwidth_remaining" -eq 0 ]; then
    echo "🚨 CRITICAL: Bandwidth exhausted - transactions will cost TRX - $address" | tee -a "$ALERT_LOG"
  fi
  
  if [ "$energy_remaining" -lt 10000 ]; then
    echo "⚠️  WARNING: Low energy ($energy_remaining remaining) - $address" | tee -a "$ALERT_LOG"
  fi
  
  if [ "$energy_remaining" -eq 0 ]; then
    echo "🚨 CRITICAL: Energy exhausted - smart contracts will be expensive - $address" | tee -a "$ALERT_LOG"
  fi
}

# Function to estimate transaction costs
estimate_transaction_cost() {
  local address=$1
  local tx_type=${2:-"transfer"}
  
  local resource_data=$(get_resources "$address")
  local total_bandwidth_remaining=$(echo "$resource_data" | jq -r '
    ((.freeNetLimit // 0) - (.freeNetUsed // 0)) + 
    ((.NetLimit // 0) - (.NetUsed // 0))
  ')
  local energy_remaining=$(echo "$resource_data" | jq -r '(.EnergyLimit // 0) - (.EnergyUsed // 0)')
  
  # Define transaction requirements
  case "$tx_type" in
    "transfer")
      local bandwidth_needed=268
      local energy_needed=0
      ;;
    "trc20")
      local bandwidth_needed=345
      local energy_needed=13000
      ;;
    "contract")
      local bandwidth_needed=345
      local energy_needed=50000
      ;;
    *)
      local bandwidth_needed=268
      local energy_needed=0
      ;;
  esac
  
  # Calculate costs
  local bandwidth_cost=0
  local energy_cost=0
  
  if [ "$bandwidth_needed" -gt "$total_bandwidth_remaining" ]; then
    local excess_bandwidth=$((bandwidth_needed - total_bandwidth_remaining))
    bandwidth_cost=$(echo "scale=6; $excess_bandwidth * 0.001" | bc -l)
  fi
  
  if [ "$energy_needed" -gt "$energy_remaining" ]; then
    local excess_energy=$((energy_needed - energy_remaining))
    energy_cost=$(echo "scale=6; $excess_energy * 0.00014" | bc -l)
  fi
  
  local total_cost=$(echo "scale=6; $bandwidth_cost + $energy_cost" | bc -l)
  
  echo "Transaction cost estimate for $tx_type:"
  echo "  Bandwidth cost: $bandwidth_cost TRX"
  echo "  Energy cost: $energy_cost TRX"
  echo "  Total cost: $total_cost TRX"
  
  if [ "$total_cost" = "0.000000" ]; then
    echo "  ✅ Transaction will be FREE"
  else
    echo "  💰 Transaction will cost $total_cost TRX"
  fi
  echo ""
}

# Function to calculate optimal staking
calculate_optimal_stake() {
  local address=$1
  local daily_txs=${2:-10}
  local daily_contracts=${3:-0}
  
  echo "=== Optimal Staking Calculation for $address ==="
  echo "Daily usage: $daily_txs transfers, $daily_contracts smart contract calls"
  
  # Calculate daily requirements
  local daily_bandwidth=$((daily_txs * 268))
  local daily_energy=$((daily_contracts * 50000))
  
  # Account for free bandwidth
  local extra_bandwidth_needed=$((daily_bandwidth > 5000 ? daily_bandwidth - 5000 : 0))
  
  # Calculate TRX staking needs (simplified ratios)
  local trx_for_bandwidth=$(echo "scale=2; $extra_bandwidth_needed / 1000" | bc -l)
  local trx_for_energy=$(echo "scale=2; $daily_energy / 4000" | bc -l)
  local total_trx=$(echo "scale=2; $trx_for_bandwidth + $trx_for_energy" | bc -l)
  
  echo "Requirements:"
  echo "  Daily bandwidth needed: $daily_bandwidth"
  echo "  Daily energy needed: $daily_energy"
  echo "  Extra bandwidth needed: $extra_bandwidth_needed"
  echo ""
  echo "Recommended staking:"
  echo "  TRX for bandwidth: $trx_for_bandwidth"
  echo "  TRX for energy: $trx_for_energy"
  echo "  Total TRX to stake: $total_trx"
  echo ""
}

# Resource monitoring function
monitor_resources() {
  local interval=${1:-300}  # Default 5 minutes
  local duration=${2:-3600} # Default 1 hour
  
  echo "Starting resource monitoring for ${#ADDRESSES[@]} addresses..."
  echo "Check interval: ${interval}s, Duration: ${duration}s"
  echo "Alerts will be logged to $ALERT_LOG"
  echo ""
  
  local end_time=$(($(date +%s) + duration))
  
  while [ $(date +%s) -lt $end_time ]; do
    echo "=== Resource Check at $(date) ==="
    
    for address in "${ADDRESSES[@]}"; do
      local resource_data=$(get_resources "$address")
      
      if [ $? -eq 0 ] && [ -n "$resource_data" ]; then
        analyze_resources "$address" "$resource_data"
      else
        echo "❌ Failed to get resources for $address"
      fi
    done
    
    echo "Sleeping for ${interval}s..."
    echo ""
    sleep "$interval"
  done
  
  echo "Resource monitoring completed."
  echo "Final alert summary:"
  cat "$ALERT_LOG" 2>/dev/null || echo "No alerts logged."
}

# Usage examples
case "${1:-status}" in
  "status")
    # Default: show status for all addresses
    for address in "${ADDRESSES[@]}"; do
      resource_data=$(get_resources "$address")
      analyze_resources "$address" "$resource_data"
    done
    ;;
  "cost")
    # Estimate transaction costs
    estimate_transaction_cost "$2" "$3"
    ;;
  "stake")
    # Calculate optimal staking
    calculate_optimal_stake "$2" "$3" "$4"
    ;;
  "monitor")
    # Start monitoring
    monitor_resources "$2" "$3"
    ;;
  *)
    echo "Usage: $0 {status|cost ADDRESS [TYPE]|stake ADDRESS [DAILY_TXS] [DAILY_CONTRACTS]|monitor [INTERVAL] [DURATION]}"
    echo ""
    echo "Examples:"
    echo "  $0 status                                    # Show resource status"
    echo "  $0 cost TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF transfer    # Estimate transfer cost"
    echo "  $0 stake TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF 10 5       # Calculate staking for 10 transfers + 5 contracts daily"
    echo "  $0 monitor 60 1800                          # Monitor for 30 minutes, check every minute"
    ;;
esac
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get account resources
async function getAccountResource(address) {
  const response = await fetch(`${TRON_API}/wallet/getaccountresource`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      address: address,
      visible: true
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Enhanced resource analyzer
class TronResourceAnalyzer {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }
  
  async getResourceStatus(address) {
    try {
      const resource = await this.getAccountResource(address);
      
      // Calculate bandwidth status
      const freeBandwidthTotal = resource.freeNetLimit || 0;
      const freeBandwidthUsed = resource.freeNetUsed || 0;
      const freeBandwidthRemaining = freeBandwidthTotal - freeBandwidthUsed;
      
      const stakedBandwidthTotal = resource.NetLimit || 0;
      const stakedBandwidthUsed = resource.NetUsed || 0;
      const stakedBandwidthRemaining = stakedBandwidthTotal - stakedBandwidthUsed;
      
      const totalBandwidth = freeBandwidthTotal + stakedBandwidthTotal;
      const totalBandwidthUsed = freeBandwidthUsed + stakedBandwidthUsed;
      const totalBandwidthRemaining = totalBandwidth - totalBandwidthUsed;
      
      // Calculate energy status
      const energyTotal = resource.EnergyLimit || 0;
      const energyUsed = resource.EnergyUsed || 0;
      const energyRemaining = energyTotal - energyUsed;
      
      return {
        address: address,
        bandwidth: {
          free: {
            total: freeBandwidthTotal,
            used: freeBandwidthUsed,
            remaining: freeBandwidthRemaining,
            usagePercent: freeBandwidthTotal > 0 ? (freeBandwidthUsed / freeBandwidthTotal * 100).toFixed(2) : 0
          },
          staked: {
            total: stakedBandwidthTotal,
            used: stakedBandwidthUsed,
            remaining: stakedBandwidthRemaining,
            usagePercent: stakedBandwidthTotal > 0 ? (stakedBandwidthUsed / stakedBandwidthTotal * 100).toFixed(2) : 0
          },
          total: {
            total: totalBandwidth,
            used: totalBandwidthUsed,
            remaining: totalBandwidthRemaining,
            usagePercent: totalBandwidth > 0 ? (totalBandwidthUsed / totalBandwidth * 100).toFixed(2) : 0
          }
        },
        energy: {
          total: energyTotal,
          used: energyUsed,
          remaining: energyRemaining,
          usagePercent: energyTotal > 0 ? (energyUsed / energyTotal * 100).toFixed(2) : 0
        },
        votingPower: resource.tronPowerLimit || 0,
        canMakeFreeTransactions: freeBandwidthRemaining > 0 || stakedBandwidthRemaining > 0,
        needsEnergyForContracts: energyRemaining === 0,
        recommendations: this.generateRecommendations(
          freeBandwidthRemaining,
          stakedBandwidthRemaining,
          energyRemaining
        )
      };
    } catch (error) {
      console.error('Error getting resource status:', error);
      throw error;
    }
  }
  
  async getAccountResource(address) {
    const response = await fetch(`${this.apiUrl}/wallet/getaccountresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ address, visible: true })
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    return await response.json();
  }
  
  generateRecommendations(freeBandwidth, stakedBandwidth, energy) {
    const recommendations = [];
    
    if (freeBandwidth <= 0 && stakedBandwidth <= 0) {
      recommendations.push({
        type: 'bandwidth',
        priority: 'high',
        message: 'No bandwidth remaining. Transactions will cost TRX.',
        action: 'Consider freezing TRX for bandwidth or wait for daily reset.'
      });
    } else if (freeBandwidth + stakedBandwidth < 1000) {
      recommendations.push({
        type: 'bandwidth',
        priority: 'medium',
        message: 'Low bandwidth remaining. Monitor usage carefully.',
        action: 'Consider reducing transaction frequency or staking TRX.'
      });
    }
    
    if (energy <= 0) {
      recommendations.push({
        type: 'energy',
        priority: 'high',
        message: 'No energy remaining. Smart contract calls will be expensive.',
        action: 'Freeze TRX for energy or rent energy from platforms like JustLend.'
      });
    } else if (energy < 50000) {
      recommendations.push({
        type: 'energy',
        priority: 'medium',
        message: 'Low energy remaining. Limit smart contract interactions.',
        action: 'Consider staking more TRX for energy.'
      });
    }
    
    if (freeBandwidth > 3000 && energy > 100000) {
      recommendations.push({
        type: 'optimization',
        priority: 'low',
        message: 'Resources are well managed.',
        action: 'Continue current staking strategy.'
      });
    }
    
    return recommendations;
  }
  
  // Calculate transaction cost estimate
  async estimateTransactionCost(address, transactionType = 'transfer') {
    try {
      const resourceStatus = await this.getResourceStatus(address);
      
      const costs = {
        transfer: { bandwidth: 268, energy: 0 },
        trc20Transfer: { bandwidth: 345, energy: 13000 },
        smartContract: { bandwidth: 345, energy: 50000 },
        vote: { bandwidth: 200, energy: 0 },
        freeze: { bandwidth: 200, energy: 0 }
      };
      
      const required = costs[transactionType] || costs.transfer;
      
      let bandwidthCost = 0;
      let energyCost = 0;
      
      // Calculate bandwidth cost
      if (required.bandwidth > resourceStatus.bandwidth.total.remaining) {
        const excessBandwidth = required.bandwidth - resourceStatus.bandwidth.total.remaining;
        bandwidthCost = excessBandwidth * 0.001; // 0.001 TRX per bandwidth point
      }
      
      // Calculate energy cost
      if (required.energy > resourceStatus.energy.remaining) {
        const excessEnergy = required.energy - resourceStatus.energy.remaining;
        energyCost = excessEnergy * 0.00014; // ~0.00014 TRX per energy unit
      }
      
      const totalCostTRX = bandwidthCost + energyCost;
      
      return {
        transactionType,
        required,
        costs: {
          bandwidth: bandwidthCost,
          energy: energyCost,
          total: totalCostTRX
        },
        willBeFree: totalCostTRX === 0,
        resourceStatus
      };
    } catch (error) {
      console.error('Error estimating transaction cost:', error);
      throw error;
    }
  }
}

// Resource monitoring dashboard
class TronResourceMonitor {
  constructor(apiKey, addresses = []) {
    this.analyzer = new TronResourceAnalyzer(apiKey);
    this.addresses = addresses;
    this.isMonitoring = false;
    this.monitoringInterval = null;
    this.alerts = [];
  }
  
  addAddress(address) {
    if (!this.addresses.includes(address)) {
      this.addresses.push(address);
    }
  }
  
  removeAddress(address) {
    this.addresses = this.addresses.filter(addr => addr !== address);
  }
  
  async checkAllResources() {
    const results = [];
    
    for (const address of this.addresses) {
      try {
        const resourceStatus = await this.analyzer.getResourceStatus(address);
        results.push({
          address,
          success: true,
          data: resourceStatus
        });
        
        // Check for alerts
        this.checkForAlerts(address, resourceStatus);
        
      } catch (error) {
        results.push({
          address,
          success: false,
          error: error.message
        });
      }
    }
    
    return results;
  }
  
  checkForAlerts(address, resourceStatus) {
    const now = Date.now();
    
    // Bandwidth alerts
    if (resourceStatus.bandwidth.total.remaining < 500) {
      this.alerts.push({
        address,
        type: 'bandwidth_low',
        message: `Low bandwidth: ${resourceStatus.bandwidth.total.remaining} remaining`,
        timestamp: now,
        severity: 'warning'
      });
    }
    
    // Energy alerts
    if (resourceStatus.energy.remaining < 10000) {
      this.alerts.push({
        address,
        type: 'energy_low',
        message: `Low energy: ${resourceStatus.energy.remaining} remaining`,
        timestamp: now,
        severity: 'warning'
      });
    }
    
    // Critical alerts
    if (resourceStatus.bandwidth.total.remaining === 0) {
      this.alerts.push({
        address,
        type: 'bandwidth_exhausted',
        message: 'Bandwidth exhausted - transactions will cost TRX',
        timestamp: now,
        severity: 'critical'
      });
    }
    
    // Keep only recent alerts (last hour)
    this.alerts = this.alerts.filter(alert => now - alert.timestamp < 3600000);
  }
  
  startMonitoring(intervalMinutes = 5) {
    if (this.isMonitoring) {
      console.log('Already monitoring resources');
      return;
    }
    
    this.isMonitoring = true;
    console.log(`Starting resource monitoring for ${this.addresses.length} addresses (${intervalMinutes}min intervals)`);
    
    this.monitoringInterval = setInterval(async () => {
      try {
        const results = await this.checkAllResources();
        const successful = results.filter(r => r.success);
        
        console.log(`Resource check complete: ${successful.length}/${results.length} successful`);
        
        // Report any new alerts
        const recentAlerts = this.alerts.filter(alert => 
          Date.now() - alert.timestamp < intervalMinutes * 60 * 1000
        );
        
        recentAlerts.forEach(alert => {
          console.log(`⚠️  ${alert.severity.toUpperCase()}: ${alert.message} (${alert.address})`);
        });
        
      } catch (error) {
        console.error('Resource monitoring error:', error);
      }
    }, intervalMinutes * 60 * 1000);
  }
  
  stopMonitoring() {
    if (this.monitoringInterval) {
      clearInterval(this.monitoringInterval);
      this.monitoringInterval = null;
    }
    this.isMonitoring = false;
    console.log('Resource monitoring stopped');
  }
  
  getAlerts(severity = null) {
    if (severity) {
      return this.alerts.filter(alert => alert.severity === severity);
    }
    return this.alerts;
  }
}

// Usage examples
(async () => {
  try {
    const analyzer = new TronResourceAnalyzer('YOUR_API_KEY');
    const address = 'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF';
    
    // Get resource status
    const resourceStatus = await analyzer.getResourceStatus(address);
    console.log('Resource Status:', resourceStatus);
    
    // Estimate transaction costs
    const transferCost = await analyzer.estimateTransactionCost(address, 'transfer');
    console.log('Transfer cost:', transferCost);
    
    const trc20Cost = await analyzer.estimateTransactionCost(address, 'trc20Transfer');
    console.log('TRC20 transfer cost:', trc20Cost);
    
    // Set up monitoring
    const monitor = new TronResourceMonitor('YOUR_API_KEY', [address]);
    monitor.startMonitoring(1); // Check every minute for demo
    
    // Stop monitoring after 5 minutes
    setTimeout(() => {
      monitor.stopMonitoring();
      console.log('Final alerts:', monitor.getAlerts());
    }, 5 * 60 * 1000);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import time
import threading
from typing import Dict, List, Optional
from datetime import datetime, timedelta

class TronResourceAnalyzer:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def get_account_resource(self, address: str) -> Dict:
        """Get raw account resource data"""
        url = f"{self.base_url}/wallet/getaccountresource"
        
        payload = {
            "address": address,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def get_resource_status(self, address: str) -> Dict:
        """Get formatted resource status with analysis"""
        try:
            resource = self.get_account_resource(address)
            
            # Calculate bandwidth status
            free_bandwidth_total = resource.get('freeNetLimit', 0)
            free_bandwidth_used = resource.get('freeNetUsed', 0)
            free_bandwidth_remaining = free_bandwidth_total - free_bandwidth_used
            
            staked_bandwidth_total = resource.get('NetLimit', 0)
            staked_bandwidth_used = resource.get('NetUsed', 0)
            staked_bandwidth_remaining = staked_bandwidth_total - staked_bandwidth_used
            
            total_bandwidth = free_bandwidth_total + staked_bandwidth_total
            total_bandwidth_used = free_bandwidth_used + staked_bandwidth_used
            total_bandwidth_remaining = total_bandwidth - total_bandwidth_used
            
            # Calculate energy status
            energy_total = resource.get('EnergyLimit', 0)
            energy_used = resource.get('EnergyUsed', 0)
            energy_remaining = energy_total - energy_used
            
            return {
                'address': address,
                'bandwidth': {
                    'free': {
                        'total': free_bandwidth_total,
                        'used': free_bandwidth_used,
                        'remaining': free_bandwidth_remaining,
                        'usage_percent': round(free_bandwidth_used / free_bandwidth_total * 100, 2) if free_bandwidth_total > 0 else 0
                    },
                    'staked': {
                        'total': staked_bandwidth_total,
                        'used': staked_bandwidth_used,
                        'remaining': staked_bandwidth_remaining,
                        'usage_percent': round(staked_bandwidth_used / staked_bandwidth_total * 100, 2) if staked_bandwidth_total > 0 else 0
                    },
                    'total': {
                        'total': total_bandwidth,
                        'used': total_bandwidth_used,
                        'remaining': total_bandwidth_remaining,
                        'usage_percent': round(total_bandwidth_used / total_bandwidth * 100, 2) if total_bandwidth > 0 else 0
                    }
                },
                'energy': {
                    'total': energy_total,
                    'used': energy_used,
                    'remaining': energy_remaining,
                    'usage_percent': round(energy_used / energy_total * 100, 2) if energy_total > 0 else 0
                },
                'voting_power': resource.get('tronPowerLimit', 0),
                'can_make_free_transactions': free_bandwidth_remaining > 0 or staked_bandwidth_remaining > 0,
                'needs_energy_for_contracts': energy_remaining == 0,
                'recommendations': self._generate_recommendations(
                    free_bandwidth_remaining,
                    staked_bandwidth_remaining,
                    energy_remaining
                )
            }
        except Exception as e:
            print(f"Error getting resource status: {e}")
            raise
    
    def _generate_recommendations(self, free_bandwidth: int, staked_bandwidth: int, energy: int) -> List[Dict]:
        """Generate resource optimization recommendations"""
        recommendations = []
        
        if free_bandwidth <= 0 and staked_bandwidth <= 0:
            recommendations.append({
                'type': 'bandwidth',
                'priority': 'high',
                'message': 'No bandwidth remaining. Transactions will cost TRX.',
                'action': 'Consider freezing TRX for bandwidth or wait for daily reset.'
            })
        elif free_bandwidth + staked_bandwidth < 1000:
            recommendations.append({
                'type': 'bandwidth',
                'priority': 'medium',
                'message': 'Low bandwidth remaining. Monitor usage carefully.',
                'action': 'Consider reducing transaction frequency or staking TRX.'
            })
        
        if energy <= 0:
            recommendations.append({
                'type': 'energy',
                'priority': 'high',
                'message': 'No energy remaining. Smart contract calls will be expensive.',
                'action': 'Freeze TRX for energy or rent energy from platforms like JustLend.'
            })
        elif energy < 50000:
            recommendations.append({
                'type': 'energy',
                'priority': 'medium',
                'message': 'Low energy remaining. Limit smart contract interactions.',
                'action': 'Consider staking more TRX for energy.'
            })
        
        if free_bandwidth > 3000 and energy > 100000:
            recommendations.append({
                'type': 'optimization',
                'priority': 'low',
                'message': 'Resources are well managed.',
                'action': 'Continue current staking strategy.'
            })
        
        return recommendations
    
    def estimate_transaction_cost(self, address: str, transaction_type: str = 'transfer') -> Dict:
        """Estimate transaction cost based on current resources"""
        try:
            resource_status = self.get_resource_status(address)
            
            # Transaction resource requirements
            costs = {
                'transfer': {'bandwidth': 268, 'energy': 0},
                'trc20_transfer': {'bandwidth': 345, 'energy': 13000},
                'smart_contract': {'bandwidth': 345, 'energy': 50000},
                'vote': {'bandwidth': 200, 'energy': 0},
                'freeze': {'bandwidth': 200, 'energy': 0}
            }
            
            required = costs.get(transaction_type, costs['transfer'])
            
            bandwidth_cost = 0
            energy_cost = 0
            
            # Calculate bandwidth cost
            bandwidth_remaining = resource_status['bandwidth']['total']['remaining']
            if required['bandwidth'] > bandwidth_remaining:
                excess_bandwidth = required['bandwidth'] - bandwidth_remaining
                bandwidth_cost = excess_bandwidth * 0.001  # 0.001 TRX per bandwidth point
            
            # Calculate energy cost
            energy_remaining = resource_status['energy']['remaining']
            if required['energy'] > energy_remaining:
                excess_energy = required['energy'] - energy_remaining
                energy_cost = excess_energy * 0.00014  # ~0.00014 TRX per energy unit
            
            total_cost_trx = bandwidth_cost + energy_cost
            
            return {
                'transaction_type': transaction_type,
                'required': required,
                'costs': {
                    'bandwidth': bandwidth_cost,
                    'energy': energy_cost,
                    'total': total_cost_trx
                },
                'will_be_free': total_cost_trx == 0,
                'resource_status': resource_status
            }
        except Exception as e:
            print(f"Error estimating transaction cost: {e}")
            raise

class TronResourceMonitor:
    def __init__(self, api_key: str, addresses: List[str] = None):
        self.analyzer = TronResourceAnalyzer(api_key)
        self.addresses = addresses or []
        self.is_monitoring = False
        self.monitoring_thread = None
        self.alerts = []
        self.monitor_interval = 300  # 5 minutes default
    
    def add_address(self, address: str):
        """Add address to monitoring list"""
        if address not in self.addresses:
            self.addresses.append(address)
    
    def remove_address(self, address: str):
        """Remove address from monitoring list"""
        if address in self.addresses:
            self.addresses.remove(address)
    
    def check_all_resources(self) -> List[Dict]:
        """Check resources for all monitored addresses"""
        results = []
        
        for address in self.addresses:
            try:
                resource_status = self.analyzer.get_resource_status(address)
                results.append({
                    'address': address,
                    'success': True,
                    'data': resource_status
                })
                
                # Check for alerts
                self._check_for_alerts(address, resource_status)
                
            except Exception as e:
                results.append({
                    'address': address,
                    'success': False,
                    'error': str(e)
                })
        
        return results
    
    def _check_for_alerts(self, address: str, resource_status: Dict):
        """Check for resource alerts"""
        now = datetime.now()
        
        # Bandwidth alerts
        bandwidth_remaining = resource_status['bandwidth']['total']['remaining']
        if bandwidth_remaining < 500:
            self.alerts.append({
                'address': address,
                'type': 'bandwidth_low',
                'message': f'Low bandwidth: {bandwidth_remaining} remaining',
                'timestamp': now,
                'severity': 'warning'
            })
        
        # Energy alerts
        energy_remaining = resource_status['energy']['remaining']
        if energy_remaining < 10000:
            self.alerts.append({
                'address': address,
                'type': 'energy_low',
                'message': f'Low energy: {energy_remaining} remaining',
                'timestamp': now,
                'severity': 'warning'
            })
        
        # Critical alerts
        if bandwidth_remaining == 0:
            self.alerts.append({
                'address': address,
                'type': 'bandwidth_exhausted',
                'message': 'Bandwidth exhausted - transactions will cost TRX',
                'timestamp': now,
                'severity': 'critical'
            })
        
        # Keep only recent alerts (last hour)
        cutoff_time = now - timedelta(hours=1)
        self.alerts = [alert for alert in self.alerts if alert['timestamp'] > cutoff_time]
    
    def start_monitoring(self, interval_minutes: int = 5):
        """Start resource monitoring"""
        if self.is_monitoring:
            print("Already monitoring resources")
            return
        
        self.monitor_interval = interval_minutes * 60
        self.is_monitoring = True
        
        print(f"Starting resource monitoring for {len(self.addresses)} addresses ({interval_minutes}min intervals)")
        
        self.monitoring_thread = threading.Thread(target=self._monitoring_loop)
        self.monitoring_thread.daemon = True
        self.monitoring_thread.start()
    
    def _monitoring_loop(self):
        """Main monitoring loop"""
        while self.is_monitoring:
            try:
                results = self.check_all_resources()
                successful = [r for r in results if r['success']]
                
                print(f"Resource check complete: {len(successful)}/{len(results)} successful")
                
                # Report any new alerts
                recent_alerts = [
                    alert for alert in self.alerts 
                    if (datetime.now() - alert['timestamp']).total_seconds() < self.monitor_interval
                ]
                
                for alert in recent_alerts:
                    print(f"⚠️  {alert['severity'].upper()}: {alert['message']} ({alert['address']})")
                
            except Exception as e:
                print(f"Resource monitoring error: {e}")
            
            time.sleep(self.monitor_interval)
    
    def stop_monitoring(self):
        """Stop resource monitoring"""
        self.is_monitoring = False
        if self.monitoring_thread:
            self.monitoring_thread.join()
        print("Resource monitoring stopped")
    
    def get_alerts(self, severity: str = None) -> List[Dict]:
        """Get alerts, optionally filtered by severity"""
        if severity:
            return [alert for alert in self.alerts if alert['severity'] == severity]
        return self.alerts

class TronResourceOptimizer:
    def __init__(self, api_key: str):
        self.analyzer = TronResourceAnalyzer(api_key)
    
    def calculate_optimal_stake(self, address: str, daily_transactions: int, 
                              smart_contract_calls: int = 0) -> Dict:
        """Calculate optimal TRX staking for bandwidth and energy"""
        try:
            # Daily bandwidth requirement
            bandwidth_per_tx = 268  # Basic transfer
            daily_bandwidth_needed = daily_transactions * bandwidth_per_tx
            
            # Daily energy requirement  
            energy_per_call = 50000  # Average smart contract call
            daily_energy_needed = smart_contract_calls * energy_per_call
            
            # Account for free bandwidth (5000 daily)
            extra_bandwidth_needed = max(0, daily_bandwidth_needed - 5000)
            
            # TRX staking calculations (simplified)
            # 1 TRX frozen = ~1000 bandwidth points or ~4000 energy
            trx_for_bandwidth = extra_bandwidth_needed / 1000
            trx_for_energy = daily_energy_needed / 4000
            
            total_trx_to_stake = trx_for_bandwidth + trx_for_energy
            
            return {
                'daily_requirements': {
                    'transactions': daily_transactions,
                    'smart_contract_calls': smart_contract_calls,
                    'bandwidth_needed': daily_bandwidth_needed,
                    'energy_needed': daily_energy_needed
                },
                'current_status': self.analyzer.get_resource_status(address),
                'recommendations': {
                    'trx_for_bandwidth': round(trx_for_bandwidth, 2),
                    'trx_for_energy': round(trx_for_energy, 2),
                    'total_trx_to_stake': round(total_trx_to_stake, 2),
                    'will_eliminate_fees': total_trx_to_stake > 0
                },
                'savings_estimate': {
                    'daily_fee_savings': round((daily_transactions * 0.268 + smart_contract_calls * 7) * 0.1, 4),
                    'monthly_fee_savings': round((daily_transactions * 0.268 + smart_contract_calls * 7) * 0.1 * 30, 2)
                }
            }
        except Exception as e:
            print(f"Error calculating optimal stake: {e}")
            raise

# Usage examples
if __name__ == "__main__":
    analyzer = TronResourceAnalyzer('YOUR_API_KEY')
    
    try:
        address = 'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF'
        
        # Get resource status
        resource_status = analyzer.get_resource_status(address)
        print("Resource Status:")
        print(f"  Bandwidth: {resource_status['bandwidth']['total']['remaining']}/{resource_status['bandwidth']['total']['total']}")
        print(f"  Energy: {resource_status['energy']['remaining']}/{resource_status['energy']['total']}")
        
        # Estimate costs
        transfer_cost = analyzer.estimate_transaction_cost(address, 'transfer')
        print(f"\nTransfer cost: {transfer_cost['costs']['total']} TRX (Free: {transfer_cost['will_be_free']})")
        
        trc20_cost = analyzer.estimate_transaction_cost(address, 'trc20_transfer')
        print(f"TRC20 transfer cost: {trc20_cost['costs']['total']} TRX (Free: {trc20_cost['will_be_free']})")
        
        # Resource optimization
        optimizer = TronResourceOptimizer('YOUR_API_KEY')
        optimization = optimizer.calculate_optimal_stake(address, daily_transactions=10, smart_contract_calls=5)
        
        print(f"\nOptimal staking:")
        print(f"  TRX for bandwidth: {optimization['recommendations']['trx_for_bandwidth']}")
        print(f"  TRX for energy: {optimization['recommendations']['trx_for_energy']}")
        print(f"  Total TRX to stake: {optimization['recommendations']['total_trx_to_stake']}")
        print(f"  Monthly savings: {optimization['savings_estimate']['monthly_fee_savings']} TRX")
        
        # Start monitoring (comment out for non-continuous examples)
        # monitor = TronResourceMonitor('YOUR_API_KEY', [address])
        # monitor.start_monitoring(1)  # Check every minute
        # time.sleep(60)  # Monitor for 1 minute
        # monitor.stop_monitoring()
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Normal Account with Resources

```json
{
  "freeNetLimit": 5000,
  "freeNetUsed": 1234,
  "NetLimit": 10000,
  "NetUsed": 2500,
  "EnergyLimit": 150000,
  "EnergyUsed": 45000,
  "tronPowerLimit": 1000000,
  "assetNetUsed": [],
  "assetNetLimit": []
}
```

### New Account (Minimal Resources)

```json
{
  "freeNetLimit": 5000,
  "freeNetUsed": 0
}
```

### Account with Token-Specific Bandwidth

```json
{
  "freeNetLimit": 5000,
  "freeNetUsed": 500,
  "NetLimit": 5000,
  "NetUsed": 1000,
  "EnergyLimit": 100000,
  "EnergyUsed": 25000,
  "tronPowerLimit": 500000,
  "assetNetUsed": [
    {
      "key": "1000001",
      "value": 100
    }
  ],
  "assetNetLimit": [
    {
      "key": "1000001", 
      "value": 1000
    }
  ]
}
```

## Common Use Cases

### 1. Wallet Resource Dashboard

```javascript
class WalletResourceDashboard {
  constructor(apiKey) {
    this.analyzer = new TronResourceAnalyzer(apiKey);
    this.updateInterval = null;
  }
  
  async createDashboard(address) {
    const resourceStatus = await this.analyzer.getResourceStatus(address);
    
    return {
      address: address,
      lastUpdated: new Date().toISOString(),
      status: {
        bandwidth: {
          percentage: resourceStatus.bandwidth.total.usagePercent,
          remaining: resourceStatus.bandwidth.total.remaining,
          status: this.getStatusLevel(resourceStatus.bandwidth.total.usagePercent),
          resetTime: this.calculateBandwidthReset()
        },
        energy: {
          percentage: resourceStatus.energy.usagePercent,
          remaining: resourceStatus.energy.remaining,
          status: this.getStatusLevel(resourceStatus.energy.usagePercent)
        }
      },
      capabilities: {
        canMakeFreeTransfers: resourceStatus.canMakeFreeTransactions,
        canCallContracts: resourceStatus.energy.remaining > 0,
        recommendedActions: resourceStatus.recommendations
      },
      estimatedCosts: await this.getEstimatedCosts(address)
    };
  }
  
  getStatusLevel(percentage) {
    if (percentage < 50) return 'good';
    if (percentage < 80) return 'warning';
    return 'critical';
  }
  
  calculateBandwidthReset() {
    const now = new Date();
    const tomorrow = new Date(now);
    tomorrow.setDate(tomorrow.getDate() + 1);
    tomorrow.setHours(0, 0, 0, 0);
    return tomorrow.toISOString();
  }
  
  async getEstimatedCosts(address) {
    const [transfer, trc20, contract] = await Promise.all([
      this.analyzer.estimateTransactionCost(address, 'transfer'),
      this.analyzer.estimateTransactionCost(address, 'trc20Transfer'),
      this.analyzer.estimateTransactionCost(address, 'smartContract')
    ]);
    
    return { transfer, trc20, contract };
  }
}
```

### 2. Smart Contract Gas Optimizer

```javascript
class TronGasOptimizer {
  constructor(apiKey) {
    this.analyzer = new TronResourceAnalyzer(apiKey);
  }
  
  async optimizeContractCall(address, estimatedEnergy) {
    const resourceStatus = await this.analyzer.getResourceStatus(address);
    const energyRemaining = resourceStatus.energy.remaining;
    
    if (energyRemaining >= estimatedEnergy) {
      return {
        strategy: 'use_staked_energy',
        cost: 0,
        message: 'Use existing staked energy - free transaction'
      };
    }
    
    const energyNeeded = estimatedEnergy - energyRemaining;
    const trxCost = energyNeeded * 0.00014;
    
    // Calculate different strategies
    const strategies = [
      {
        strategy: 'pay_with_trx',
        cost: trxCost,
        message: `Pay ${trxCost.toFixed(6)} TRX for energy`
      },
      {
        strategy: 'stake_trx',
        cost: energyNeeded / 4000, // Simplified ratio
        message: `Stake ${(energyNeeded / 4000).toFixed(2)} TRX for energy`,
        benefits: 'Reusable energy for future transactions'
      },
      {
        strategy: 'rent_energy',
        cost: trxCost * 0.7, // Assume 30% savings
        message: `Rent energy for ${(trxCost * 0.7).toFixed(6)} TRX`,
        benefits: 'Lower cost for one-time use'
      }
    ];
    
    // Sort by cost
    strategies.sort((a, b) => a.cost - b.cost);
    
    return {
      energyNeeded,
      currentEnergy: energyRemaining,
      requiredEnergy: estimatedEnergy,
      recommendedStrategy: strategies[0],
      allStrategies: strategies
    };
  }
}
```

### 3. Resource Alert System

```javascript
class TronResourceAlertSystem {
  constructor(apiKey) {
    this.analyzer = new TronResourceAnalyzer(apiKey);
    this.alertCallbacks = new Map();
    this.thresholds = {
      bandwidth: { warning: 1000, critical: 100 },
      energy: { warning: 20000, critical: 5000 }
    };
  }
  
  onAlert(type, callback) {
    if (!this.alertCallbacks.has(type)) {
      this.alertCallbacks.set(type, []);
    }
    this.alertCallbacks.get(type).push(callback);
  }
  
  async checkAndAlert(address) {
    try {
      const resourceStatus = await this.analyzer.getResourceStatus(address);
      
      // Check bandwidth alerts
      const bandwidthRemaining = resourceStatus.bandwidth.total.remaining;
      if (bandwidthRemaining <= this.thresholds.bandwidth.critical) {
        this.triggerAlert('bandwidth_critical', {
          address,
          remaining: bandwidthRemaining,
          severity: 'critical',
          message: 'Bandwidth critically low - transactions will cost TRX'
        });
      } else if (bandwidthRemaining <= this.thresholds.bandwidth.warning) {
        this.triggerAlert('bandwidth_warning', {
          address,
          remaining: bandwidthRemaining,
          severity: 'warning',
          message: 'Bandwidth running low'
        });
      }
      
      // Check energy alerts
      const energyRemaining = resourceStatus.energy.remaining;
      if (energyRemaining <= this.thresholds.energy.critical) {
        this.triggerAlert('energy_critical', {
          address,
          remaining: energyRemaining,
          severity: 'critical',
          message: 'Energy critically low - smart contracts will be expensive'
        });
      } else if (energyRemaining <= this.thresholds.energy.warning) {
        this.triggerAlert('energy_warning', {
          address,
          remaining: energyRemaining,
          severity: 'warning',
          message: 'Energy running low'
        });
      }
      
    } catch (error) {
      this.triggerAlert('error', {
        address,
        error: error.message,
        severity: 'error',
        message: 'Failed to check resources'
      });
    }
  }
  
  triggerAlert(type, data) {
    const callbacks = this.alertCallbacks.get(type) || [];
    callbacks.forEach(callback => {
      try {
        callback(data);
      } catch (error) {
        console.error('Alert callback error:', error);
      }
    });
  }
  
  setThreshold(resource, level, value) {
    if (this.thresholds[resource] && this.thresholds[resource][level] !== undefined) {
      this.thresholds[resource][level] = value;
    }
  }
}
```

## Performance Tips

1. **Cache Resource Data** - Resources update slowly, cache for 30-60 seconds
2. **Batch Monitoring** - Check multiple addresses in sequence with slight delays
3. **Smart Polling** - Increase check frequency when resources are low
4. **Alert Optimization** - Use thresholds to avoid alert spam

```javascript
// Optimized resource monitoring with smart intervals
class SmartResourceMonitor {
  constructor(apiKey) {
    this.analyzer = new TronResourceAnalyzer(apiKey);
    this.cache = new Map();
    this.dynamicIntervals = new Map();
  }
  
  async monitorWithSmartIntervals(address) {
    const resourceStatus = await this.analyzer.getResourceStatus(address);
    
    // Determine monitoring frequency based on resource levels
    const bandwidthPercent = resourceStatus.bandwidth.total.usagePercent;
    const energyPercent = resourceStatus.energy.usagePercent;
    
    let interval;
    if (bandwidthPercent > 90 || energyPercent > 90) {
      interval = 60000; // 1 minute for critical
    } else if (bandwidthPercent > 70 || energyPercent > 70) {
      interval = 300000; // 5 minutes for warning
    } else {
      interval = 1800000; // 30 minutes for normal
    }
    
    this.dynamicIntervals.set(address, interval);
    
    // Cache result
    this.cache.set(address, {
      data: resourceStatus,
      timestamp: Date.now(),
      ttl: Math.min(interval / 2, 60000) // Cache for half the interval, max 1 minute
    });
    
    return resourceStatus;
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/getblockbyid - Get TRON Block by Hash

# wallet/getblockbyid - Get TRON Block by Hash

Get block information by block hash ID.

## Endpoint

```
POST /wallet/getblockbyid
```

## Request Parameters

- `value` (`string, required`): Required parameter: Block hash ID (hex string)
- `detail` (`boolean, required`): Optional parameter: Include full transaction details (default: false)

## Request Example

```bash
# Get block by hash ID
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid \
      -H "Content-Type: application/json" \
      -d '{
        "value": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9"
      }'

    # Get block with full transaction details
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid \
      -H "Content-Type: application/json" \
      -d '{
        "value": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
        "detail": true
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `blockID` - Block hash identifier `block_header` - Block header information `raw_data` - Raw block data `number` - Block height `txTrieRoot` - Transaction trie root `witness_address` - Block producer address `parentHash` - Parent block hash `timestamp` - Block timestamp (milliseconds) `version` - Block version `witness_signature` - Witness signature `transactions` - Array of transactions in the block

## Successful Response

```json
{
  "blockID": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
  "block_header": {
    "raw_data": {
      "number": 58234567,
      "txTrieRoot": "7d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9c8d7e8f9c8d7e8f9",
      "witness_address": "41928c9af0651632157ef27a2cf17ca72c575a4d21",
      "parentHash": "0000000003787ac64d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f8",
      "version": 27,
      "timestamp": 1702456789000
    },
    "witness_signature": "a3e5b8c9d7f8e9c8d7e8f9c8d7e8f9..."
  },
  "transactions": [
    {
      "txID": "7c2d4206c03a883dd9066d6c839d0deaef32dc5a0d9b15f6d06e506906c90332",
      "raw_data": {
        "contract": [
          {
            "parameter": {
              "value": {
                "amount": 1000000,
                "owner_address": "41e552726909b5c951a9e0d365674e5a48b46f79d3",
                "to_address": "41d1e7a6bc354106cb410e65ff8b181c600ff14292"
              },
              "type_url": "type.googleapis.com/protocol.TransferContract"
            },
            "type": "TransferContract"
          }
        ],
        "ref_block_bytes": "7ac6",
        "ref_block_hash": "4d9bb8f8c9c59ac3",
        "expiration": 1702456849000,
        "timestamp": 1702456789000
      },
      "signature": ["b8c9d7e8f9c8d7e8f9c8d7e8f9..."]
    }
  ]
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get block by hash ID
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid \
  -H "Content-Type: application/json" \
  -d '{
    "value": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9"
  }'

# Get block with full transaction details
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid \
  -H "Content-Type: application/json" \
  -d '{
    "value": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
    "detail": true
  }'
```

```javascript
// Get block by hash ID
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    value: '0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9'
  }),
});

const data = await response.json();
console.log(data);

// Get block with full transaction details
const detailedResponse = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    value: '0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9',
    detail: true
  }),
});

const detailedData = await detailedResponse.json();
console.log(detailedData);
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbyid"

# Basic block query
payload = {
    "value": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9"
}

response = requests.post(url, json=payload)
print(response.json())

# Get block with transaction details
detailed_payload = {
    "value": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
    "detail": True
}

detailed_response = requests.post(url, json=detailed_payload)
print(detailed_response.json())
```

## Use Cases

- **Block Verification**: Verify block contents by hash
- **Transaction Confirmation**: Confirm transaction inclusion in specific block
- **Chain Reorganization Detection**: Monitor for block hash changes
- **Block Explorer**: Display block details by hash
- **Forensic Analysis**: Investigate specific blocks

## Related Methods

- [wallet/getblockbynum](https://www.dwellir.com/docs/tron/wallet-getblockbynum) - Get block by height
- [wallet/getblockbylatestnum](https://www.dwellir.com/docs/tron/wallet-getblockbylatestnum) - Get recent blocks
- [wallet/getnowblock](https://www.dwellir.com/docs/tron/wallet-getnowblock) - Get latest block
- [wallet/gettransactionbyid](https://www.dwellir.com/docs/tron/wallet-gettransactionbyid) - Get transaction details

---

## wallet/getblockbylatestnum - Get Recent TRON Bl...

# wallet/getblockbylatestnum - Get Recent TRON Bl...

Get a range of recent blocks counting backwards from the latest block.

## Endpoint

```
POST /wallet/getblockbylatestnum
```

## Request Parameters

- `num` (`number, required`): Required parameter: Number of recent blocks to retrieve (max: 99)

## Request Example

```bash
# Get last 5 blocks
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum \
      -H "Content-Type: application/json" \
      -d '{
        "num": 5
      }'

    # Get last 20 blocks
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum \
      -H "Content-Type: application/json" \
      -d '{
        "num": 20
      }'

    # Get maximum allowed (99 blocks)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum \
      -H "Content-Type: application/json" \
      -d '{
        "num": 99
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `blockID` - Block hash identifier `block_header` - Block header information `raw_data` - Raw block data `number` - Block height `txTrieRoot` - Transaction trie root `witness_address` - Block producer address `parentHash` - Parent block hash `timestamp` - Block timestamp (milliseconds) `version` - Block version `witness_signature` - Witness signature `transactions` - Array of transactions in each block

## Successful Response

```json
[
  {
    "blockID": "0000000003787ac94d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8fa",
    "block_header": {
      "raw_data": {
        "number": 58234569,
        "txTrieRoot": "8e9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9c8d7e8f9c8d7e8fa",
        "witness_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c",
        "parentHash": "0000000003787ac84d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
        "version": 27,
        "timestamp": 1702456795000
      },
      "witness_signature": "b4e6b8c9d7f8e9c8d7e8f9c8d7e8f9..."
    },
    "transactions": []
  },
  {
    "blockID": "0000000003787ac84d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
    "block_header": {
      "raw_data": {
        "number": 58234568,
        "txTrieRoot": "7e9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9c8d7e8f9c8d7e8f9",
        "witness_address": "41928c9af0651632157ef27a2cf17ca72c575a4d21",
        "parentHash": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f8",
        "version": 27,
        "timestamp": 1702456792000
      },
      "witness_signature": "a4e5b8c9d7f8e9c8d7e8f9c8d7e8f9..."
    },
    "transactions": [
      {
        "txID": "8d3e5f9a7b6c4d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e",
        "raw_data": {
          "contract": [
            {
              "parameter": {
                "value": {
                  "amount": 2000000,
                  "owner_address": "41d1e7a6bc354106cb410e65ff8b181c600ff14292",
                  "to_address": "41e552726909b5c951a9e0d365674e5a48b46f79d3"
                },
                "type_url": "type.googleapis.com/protocol.TransferContract"
              },
              "type": "TransferContract"
            }
          ],
          "ref_block_bytes": "7ac7",
          "ref_block_hash": "5d9bb8f8c9c59ac4",
          "expiration": 1702456852000,
          "timestamp": 1702456792000
        },
        "signature": ["c8c9d7e8f9c8d7e8f9c8d7e8f9..."]
      }
    ]
  }
]
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get last 5 blocks
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum \
  -H "Content-Type: application/json" \
  -d '{
    "num": 5
  }'

# Get last 20 blocks
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum \
  -H "Content-Type: application/json" \
  -d '{
    "num": 20
  }'

# Get maximum allowed (99 blocks)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum \
  -H "Content-Type: application/json" \
  -d '{
    "num": 99
  }'
```

```javascript
// Get last 5 blocks
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    num: 5
  }),
});

const blocks = await response.json();
console.log(`Retrieved ${blocks.length} recent blocks`);

// Process recent blocks
blocks.forEach(block => {
  console.log(`Block ${block.block_header.raw_data.number}: ${block.transactions.length} transactions`);
});

// Get larger range for analysis
const analysisResponse = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    num: 50  // Get last 50 blocks
  }),
});

const analysisBlocks = await analysisResponse.json();

// Analyze block production
const blockTimes = analysisBlocks.map(block => block.block_header.raw_data.timestamp);
const avgBlockTime = (blockTimes[0] - blockTimes[blockTimes.length - 1]) / (blockTimes.length - 1);
console.log(`Average block time: ${avgBlockTime}ms`);
```

```python
import requests
from datetime import datetime

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbylatestnum"

# Get last 10 blocks
payload = {
    "num": 10
}

response = requests.post(url, json=payload)
blocks = response.json()

print(f"Retrieved {len(blocks)} recent blocks")

# Analyze blocks
for block in blocks:
    block_num = block['block_header']['raw_data']['number']
    tx_count = len(block.get('transactions', []))
    timestamp = datetime.fromtimestamp(
        block['block_header']['raw_data']['timestamp'] / 1000
    )
    print(f"Block {block_num}: {tx_count} txs at {timestamp}")

# Get more blocks for statistics
stats_payload = {
    "num": 30
}

stats_response = requests.post(url, json=stats_payload)
stats_blocks = stats_response.json()

# Calculate statistics
total_txs = sum(len(b.get('transactions', [])) for b in stats_blocks)
avg_txs_per_block = total_txs / len(stats_blocks)
print(f"\nAverage transactions per block: {avg_txs_per_block:.2f}")
```

## Use Cases

- **Real-time Monitoring**: Track latest blockchain activity
- **Transaction Confirmation**: Check recent blocks for transaction inclusion
- **Network Health**: Monitor block production rate and consistency
- **Statistical Analysis**: Analyze recent blockchain metrics
- **Block Explorer**: Display recent blocks on explorer homepage

## Related Methods

- [wallet/getnowblock](https://www.dwellir.com/docs/tron/wallet-getnowblock) - Get single latest block
- [wallet/getblockbynum](https://www.dwellir.com/docs/tron/wallet-getblockbynum) - Get specific block by height
- [wallet/getblockbyid](https://www.dwellir.com/docs/tron/wallet-getblockbyid) - Get block by hash ID
- [wallet/gettransactionbyid](https://www.dwellir.com/docs/tron/wallet-gettransactionbyid) - Get transaction details

---

## wallet/getblockbynum - Get TRON Block by Height

# wallet/getblockbynum - Get TRON Block by Height

Get block information by block height number.

## Endpoint

```
POST /wallet/getblockbynum
```

## Request Parameters

- `num` (`number, required`): Required parameter: Block height number

## Request Example

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbynum \
      -H "Content-Type: application/json" \
      -d '{
        "num": 58234567
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `blockID` - Block hash `block_header` - Block header information `raw_data` - Raw block data `number` - Block height `txTrieRoot` - Transaction trie root `witness_address` - Block producer address `parentHash` - Parent block hash `timestamp` - Block timestamp `witness_signature` - Witness signature `transactions` - Array of transactions in the block

## Successful Response

```json
{
  "blockID": "0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9",
  "block_header": {
    "raw_data": {
      "number": 58234567,
      "txTrieRoot": "7d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f9c8d7e8f9c8d7e8f9",
      "witness_address": "41928c9af0651632157ef27a2cf17ca72c575a4d21",
      "parentHash": "0000000003787ac64d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9c8d7e8f9c8d7e8f8",
      "version": 27,
      "timestamp": 1702456789000
    },
    "witness_signature": "a3e5b8c9d7f8e9c8d7e8f9c8d7e8f9..."
  },
  "transactions": [
    {
      "txID": "7c2d4206c03a883dd9066d6c839d0deaef32dc5a0d9b15f6d06e506906c90332",
      "raw_data": {
        "contract": [
          {
            "parameter": {
              "value": {
                "amount": 1000000,
                "owner_address": "41e552726909b5c951a9e0d365674e5a48b46f79d3",
                "to_address": "41d1e7a6bc354106cb410e65ff8b181c600ff14292"
              },
              "type_url": "type.googleapis.com/protocol.TransferContract"
            },
            "type": "TransferContract"
          }
        ],
        "ref_block_bytes": "7ac6",
        "ref_block_hash": "4d9bb8f8c9c59ac3",
        "expiration": 1702456849000,
        "timestamp": 1702456789000
      },
      "signature": ["b8c9d7e8f9c8d7e8f9c8d7e8f9..."]
    }
  ]
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbynum \
  -H "Content-Type: application/json" \
  -d '{
    "num": 58234567
  }'
```

```javascript
// Get block by height number
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbynum', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    num: 58234567
  }),
});

const data = await response.json();
console.log(data);
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getblockbynum"
payload = {
    "num": 58234567
}

response = requests.post(url, json=payload)
print(response.json())
```

## Use Cases

- **Block Explorer**: Display block details and transactions
- **Transaction Verification**: Confirm transaction inclusion
- **Chain Analysis**: Analyze block production patterns
- **Data Indexing**: Index historical blockchain data
- **Network Monitoring**: Track block production rate

## Related Methods

- [wallet/getnowblock](https://www.dwellir.com/docs/tron/wallet-getnowblock) - Get latest block
- [wallet/gettransactionbyid](https://www.dwellir.com/docs/tron/wallet-gettransactionbyid) - Get transaction details
- [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount) - Get account information

---

## wallet/getchainparameters - Get TRON Chain Para...

# wallet/getchainparameters - Get TRON Chain Para...

Get current blockchain parameters including fees, voting settings, and resource configurations. This endpoint returns the governance-controlled parameters that define TRON's fee structure, resource limits, and feature flags.

## Overview

TRON's chain parameters are set through Super Representative voting and governance proposals. They control critical aspects of the network including energy prices, bandwidth allocation, account creation fees, and TVM feature enablement. Applications that interact with TRON should query these parameters to calculate accurate transaction costs and verify network capabilities.

If you are building a payment system on TRON (especially for USDT TRC-20 transfers), the `getEnergyFee` and `getTransactionFee` parameters are essential for accurate cost estimation. Combine this with [`wallet/estimateenergy`](https://www.dwellir.com/docs/tron/wallet-estimateenergy) for precise per-transaction fee forecasting.

## Endpoint

```
POST /wallet/getchainparameters
```

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Get chain parameters
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getchainparameters \
      -H "Content-Type: application/json" \
      -d '{}'

    # Parse specific parameter (using jq)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getchainparameters \
      -H "Content-Type: application/json" \
      -d '{}' | jq '.chainParameter[] | select(.key == "getEnergyFee")'
```

## Response Fields

- `chainParameter` (`array, required`): Array of chain parameter objects with `key` and `value` fields.

## Successful Response

```json
{
  "chainParameter": [
    {
      "key": "getMaintenanceTimeInterval",
      "value": 21600000
    },
    {
      "key": "getAccountUpgradeCost",
      "value": 9999000000
    },
    {
      "key": "getCreateAccountFee",
      "value": 100000
    },
    {
      "key": "getTransactionFee",
      "value": 1000
    },
    {
      "key": "getEnergyFee",
      "value": 100
    },
    {
      "key": "getMaxCpuTimeOfOneTx",
      "value": 80
    },
    {
      "key": "getFreeNetLimit",
      "value": 600
    },
    {
      "key": "getTotalEnergyLimit",
      "value": 180000000000
    },
    {
      "key": "getAllowDelegateResource",
      "value": 1
    },
    {
      "key": "getAllowMultiSign",
      "value": 1
    },
    {
      "key": "getWitnessPayPerBlock",
      "value": 8000000
    },
    {
      "key": "getWitness127PayPerBlock",
      "value": 128000000
    },
    {
      "key": "getAllowTvmShangHai",
      "value": 1
    }
  ]
}
```

## Error Responses

### Error 1

### Error 2

### Error 3

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get chain parameters
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getchainparameters \
  -H "Content-Type: application/json" \
  -d '{}'

# Parse specific parameter (using jq)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getchainparameters \
  -H "Content-Type: application/json" \
  -d '{}' | jq '.chainParameter[] | select(.key == "getEnergyFee")'
```

```javascript
// Get chain parameters
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getchainparameters', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({}),
});

const data = await response.json();

// Parse parameters into usable format
const parameters = {};
data.chainParameter.forEach(param => {
  parameters[param.key] = param.value;
});

console.log('Chain Parameters:', parameters);

// Calculate fees
const createAccountFee = parameters.getCreateAccountFee / 1000000; // Convert to TRX
const transactionFee = parameters.getTransactionFee / 1000000;
const energyPrice = parameters.getEnergyFee / 1000000;

console.log(`Create Account Fee: ${createAccountFee} TRX`);
console.log(`Transaction Fee: ${transactionFee} TRX`);
console.log(`Energy Price: ${energyPrice} TRX per unit`);
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getchainparameters"

response = requests.post(url, json={})
data = response.json()

# Parse parameters
parameters = {}
for param in data['chainParameter']:
    parameters[param['key']] = param['value']

print("Chain Parameters:")
for key, value in parameters.items():
    print(f"  {key}: {value}")

# Extract important fees
create_account_fee = parameters.get('getCreateAccountFee', 0) / 1_000_000
transaction_fee = parameters.get('getTransactionFee', 0) / 1_000_000
energy_price = parameters.get('getEnergyFee', 0) / 1_000_000

print(f"\nFees (in TRX):")
print(f"  Create Account: {create_account_fee}")
print(f"  Transaction: {transaction_fee}")
print(f"  Energy Price: {energy_price} per unit")

# Check network limits
free_bandwidth = parameters.get('getFreeNetLimit', 0)
total_energy = parameters.get('getTotalEnergyLimit', 0)

print(f"\nResource Limits:")
print(f"  Free Daily Bandwidth: {free_bandwidth}")
print(f"  Total Network Energy: {total_energy:,}")
```

## Use Cases

- **Fee Calculation**: Calculate transaction costs before execution
- **Resource Planning**: Understand energy and bandwidth pricing
- **Network Monitoring**: Track parameter changes over time
- **DApp Configuration**: Adjust application based on network settings
- **Governance Tracking**: Monitor voting and proposal parameters

## Related Methods

- [wallet/getaccountresource](https://www.dwellir.com/docs/tron/wallet-getaccountresource) - Get account resources
- [wallet/getnodeinfo](https://www.dwellir.com/docs/tron/wallet-getnodeinfo) - Get node information
- [wallet/estimateenergy](https://www.dwellir.com/docs/tron/wallet-estimateenergy) - Estimate energy consumption
- [eth\_gasPrice](https://www.dwellir.com/docs/tron/eth_gasPrice) - EVM-compatible gas price (derived from energy price)

---

## wallet/getcontract - Get TRON Smart Contract Info

# wallet/getcontract - Get TRON Smart Contract Info

**Dwellir's TRON endpoints** provide complete smart contract information including bytecode and metadata.
Build contract explorers and verification tools with our optimized contract data API.

[Explore smart contracts](https://dashboard.dwellir.com/register)

Retrieves comprehensive information about a deployed smart contract on the TRON network, including bytecode, ABI, creator details, and deployment information.

## When to Use This Method

`wallet/getcontract` is essential for:

- **Contract Verification** - Verify deployed contract matches source code
- **ABI Retrieval** - Get contract interface for interaction
- **Contract Analysis** - Analyze contract functionality and security
- **Block Explorers** - Display contract information to users
- **Development Tools** - Build contract interaction interfaces

## Request Parameters

- `value` (`string, required`): Smart contract address in Base58 format Example: `"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"` (USDT contract)
- `visible` (`boolean, optional`): `true` - Use Base58 address format in response `false` - Use hex address format in response

## Request Example

```json
{
  "value": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "visible": true
}
```

## Response Fields

- `result` (`OBJECT, required`): `bytecode` - Contract bytecode (hex string) `name` - Contract name (if available) `abi` - Contract ABI (if available) `origin_address` - Contract creator address `origin_energy_limit` - Energy limit set by creator `contract_address` - Contract address `code_hash` - Hash of the contract code

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get contract information
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "visible": true
  }'

# Extract key contract information
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "visible": true
  }' | jq '{
    address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    has_contract: (.bytecode != null and .bytecode != ""),
    creator: .origin_address,
    energy_limit: .origin_energy_limit,
    name: .name // "Unknown",
    has_abi: (.abi != null and .abi != ""),
    bytecode_size: (.bytecode | length) / 2,
    code_hash: .code_hash
  }'
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get contract information
async function getContract(contractAddress) {
  const response = await fetch(`${TRON_API}/wallet/getcontract`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      value: contractAddress,
      visible: true
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Smart contract analyzer
class TronContractAnalyzer {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }
  
  async getContractInfo(contractAddress) {
    try {
      const contract = await this.getContract(contractAddress);
      
      if (!contract.bytecode) {
        return {
          exists: false,
          address: contractAddress,
          message: 'Contract not found or not deployed'
        };
      }
      
      return {
        exists: true,
        address: contractAddress,
        bytecode: contract.bytecode,
        codeHash: contract.code_hash,
        creator: contract.origin_address,
        energyLimit: contract.origin_energy_limit || 0,
        name: contract.name || 'Unknown',
        abi: this.parseABI(contract.abi),
        isVerified: !!contract.abi,
        functions: this.extractFunctions(contract.abi),
        events: this.extractEvents(contract.abi),
        analysis: this.analyzeContract(contract)
      };
    } catch (error) {
      console.error('Error getting contract info:', error);
      throw error;
    }
  }
  
  async getContract(contractAddress) {
    const response = await fetch(`${this.apiUrl}/wallet/getcontract`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ value: contractAddress, visible: true })
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    return await response.json();
  }
  
  parseABI(abiString) {
    if (!abiString) return null;
    
    try {
      if (typeof abiString === 'string') {
        return JSON.parse(abiString);
      }
      return abiString;
    } catch (error) {
      console.warn('Failed to parse ABI:', error);
      return null;
    }
  }
  
  extractFunctions(abi) {
    if (!abi || !Array.isArray(abi)) return [];
    
    return abi
      .filter(item => item.type === 'function')
      .map(func => ({
        name: func.name,
        type: func.stateMutability || 'nonpayable',
        inputs: func.inputs || [],
        outputs: func.outputs || [],
        signature: this.buildFunctionSignature(func),
        isView: func.stateMutability === 'view' || func.stateMutability === 'pure',
        isPayable: func.stateMutability === 'payable'
      }));
  }
  
  extractEvents(abi) {
    if (!abi || !Array.isArray(abi)) return [];
    
    return abi
      .filter(item => item.type === 'event')
      .map(event => ({
        name: event.name,
        inputs: event.inputs || [],
        signature: this.buildEventSignature(event),
        anonymous: event.anonymous || false
      }));
  }
  
  buildFunctionSignature(func) {
    const inputs = func.inputs?.map(input => input.type).join(',') || '';
    return `${func.name}(${inputs})`;
  }
  
  buildEventSignature(event) {
    const inputs = event.inputs?.map(input => input.type).join(',') || '';
    return `${event.name}(${inputs})`;
  }
  
  analyzeContract(contract) {
    const bytecode = contract.bytecode || '';
    const abi = this.parseABI(contract.abi);
    
    return {
      bytecodeSize: Math.floor(bytecode.length / 2), // Convert hex to bytes
      hasConstructor: abi?.some(item => item.type === 'constructor') || false,
      hasFallback: abi?.some(item => item.type === 'fallback') || false,
      hasReceive: abi?.some(item => item.type === 'receive') || false,
      functionCount: abi?.filter(item => item.type === 'function').length || 0,
      eventCount: abi?.filter(item => item.type === 'event').length || 0,
      hasPayableFunctions: abi?.some(item => 
        item.type === 'function' && item.stateMutability === 'payable'
      ) || false,
      isProxy: this.detectProxy(bytecode, abi),
      isToken: this.detectTokenStandard(abi),
      securityFlags: this.analyzeSecurityFeatures(abi)
    };
  }
  
  detectProxy(bytecode, abi) {
    // Simplified proxy detection - look for delegate call patterns
    const proxyPatterns = [
      '3660006000376110006000366000f3', // Minimal proxy pattern
      'delegatecall' // Contains delegate call
    ];
    
    return proxyPatterns.some(pattern => 
      bytecode.toLowerCase().includes(pattern.toLowerCase())
    );
  }
  
  detectTokenStandard(abi) {
    if (!abi || !Array.isArray(abi)) return null;
    
    const functions = abi.filter(item => item.type === 'function').map(f => f.name);
    const events = abi.filter(item => item.type === 'event').map(e => e.name);
    
    // Check for TRC20 standard
    const trc20Functions = ['totalSupply', 'balanceOf', 'transfer', 'transferFrom', 'approve', 'allowance'];
    const trc20Events = ['Transfer', 'Approval'];
    
    const hasTRC20Functions = trc20Functions.every(func => functions.includes(func));
    const hasTRC20Events = trc20Events.every(event => events.includes(event));
    
    if (hasTRC20Functions && hasTRC20Events) {
      return 'TRC20';
    }
    
    // Check for TRC721 standard
    const trc721Functions = ['balanceOf', 'ownerOf', 'approve', 'getApproved', 'setApprovalForAll', 'isApprovedForAll', 'transferFrom', 'safeTransferFrom'];
    const hasTRC721Functions = trc721Functions.every(func => functions.includes(func));
    
    if (hasTRC721Functions) {
      return 'TRC721';
    }
    
    return null;
  }
  
  analyzeSecurityFeatures(abi) {
    if (!abi || !Array.isArray(abi)) return [];
    
    const flags = [];
    const functions = abi.filter(item => item.type === 'function');
    
    // Check for common security patterns
    const hasOwner = functions.some(f => f.name.toLowerCase().includes('owner'));
    const hasPause = functions.some(f => 
      f.name.toLowerCase().includes('pause') || f.name.toLowerCase().includes('emergency')
    );
    const hasUpgrade = functions.some(f => f.name.toLowerCase().includes('upgrade'));
    const hasTimelock = functions.some(f => f.name.toLowerCase().includes('timelock'));
    
    if (hasOwner) flags.push('Ownable');
    if (hasPause) flags.push('Pausable');
    if (hasUpgrade) flags.push('Upgradeable');
    if (hasTimelock) flags.push('Timelock');
    
    return flags;
  }
}

// Contract verification helper
class TronContractVerifier {
  constructor(apiKey) {
    this.analyzer = new TronContractAnalyzer(apiKey);
  }
  
  async verifyContract(contractAddress, sourceCode, compilerVersion, optimized = false) {
    try {
      const contractInfo = await this.analyzer.getContractInfo(contractAddress);
      
      if (!contractInfo.exists) {
        return {
          verified: false,
          reason: 'Contract not found on blockchain'
        };
      }
      
      // In a real implementation, you would:
      // 1. Compile the source code with the specified compiler
      // 2. Compare the resulting bytecode with the deployed bytecode
      // 3. Handle constructor arguments and optimization settings
      
      // Simplified verification check
      const verification = this.simulateVerification(
        contractInfo.bytecode,
        sourceCode,
        compilerVersion,
        optimized
      );
      
      return {
        verified: verification.matches,
        contractInfo,
        verification: {
          sourceBytecodeHash: verification.sourceHash,
          deployedBytecodeHash: contractInfo.codeHash,
          matches: verification.matches,
          compilerVersion,
          optimized
        },
        reason: verification.matches ? 'Contract verified successfully' : 'Bytecode mismatch'
      };
      
    } catch (error) {
      return {
        verified: false,
        reason: `Verification error: ${error.message}`
      };
    }
  }
  
  simulateVerification(deployedBytecode, sourceCode, compilerVersion, optimized) {
    // This is a simplified simulation - real verification requires:
    // - Solidity compiler integration
    // - Constructor argument handling
    // - Library linking
    // - Optimization setting matching
    
    const sourceHash = this.hashString(sourceCode);
    const deployedHash = this.hashString(deployedBytecode);
    
    // In reality, you'd compile and compare actual bytecode
    return {
      matches: false, // Would be true if bytecode matches
      sourceHash,
      deployedHash
    };
  }
  
  hashString(str) {
    // Simple hash function for demo - use proper crypto hash in production
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // Convert to 32-bit integer
    }
    return hash.toString(16);
  }
}

// Contract interaction helper
class TronContractInteractor {
  constructor(apiKey) {
    this.analyzer = new TronContractAnalyzer(apiKey);
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }
  
  async generateInteractionInterface(contractAddress) {
    try {
      const contractInfo = await this.analyzer.getContractInfo(contractAddress);
      
      if (!contractInfo.exists) {
        throw new Error('Contract not found');
      }
      
      const interface = {
        address: contractAddress,
        name: contractInfo.name,
        isVerified: contractInfo.isVerified,
        functions: {
          view: contractInfo.functions.filter(f => f.isView),
          write: contractInfo.functions.filter(f => !f.isView),
          payable: contractInfo.functions.filter(f => f.isPayable)
        },
        events: contractInfo.events,
        standards: contractInfo.analysis.isToken ? [contractInfo.analysis.isToken] : [],
        interactionExamples: this.generateExamples(contractInfo)
      };
      
      return interface;
    } catch (error) {
      console.error('Error generating interface:', error);
      throw error;
    }
  }
  
  generateExamples(contractInfo) {
    const examples = [];
    
    // Generate examples for common functions
    const viewFunctions = contractInfo.functions.filter(f => f.isView && f.inputs.length === 0);
    const tokenFunctions = contractInfo.functions.filter(f => 
      ['balanceOf', 'totalSupply', 'name', 'symbol', 'decimals'].includes(f.name)
    );
    
    // Add view function examples
    viewFunctions.slice(0, 3).forEach(func => {
      examples.push({
        type: 'view',
        function: func.name,
        description: `Get ${func.name} information`,
        code: `// Call ${func.signature}\nconst result = await triggerSmartContract('${contractInfo.address}', '${func.signature}', '', ownerAddress);`
      });
    });
    
    // Add token-specific examples if it's a token
    if (contractInfo.analysis.isToken === 'TRC20') {
      examples.push({
        type: 'token',
        function: 'balanceOf',
        description: 'Get token balance for an address',
        code: `// Get TRC20 token balance\nconst balance = await getTokenBalance('${contractInfo.address}', 'USER_ADDRESS');`
      });
    }
    
    return examples;
  }
}

// Usage examples
(async () => {
  try {
    const analyzer = new TronContractAnalyzer('YOUR_API_KEY');
    const usdtContract = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
    
    // Get contract information
    const contractInfo = await analyzer.getContractInfo(usdtContract);
    console.log('Contract Info:', contractInfo.name);
    console.log('Is Token:', contractInfo.analysis.isToken);
    console.log('Function Count:', contractInfo.analysis.functionCount);
    console.log('Is Verified:', contractInfo.isVerified);
    
    // Generate interaction interface
    const interactor = new TronContractInteractor('YOUR_API_KEY');
    const interface = await interactor.generateInteractionInterface(usdtContract);
    console.log('View Functions:', interface.functions.view.length);
    console.log('Write Functions:', interface.functions.write.length);
    
    // Verify contract (simulation)
    const verifier = new TronContractVerifier('YOUR_API_KEY');
    const verification = await verifier.verifyContract(
      usdtContract,
      'contract source code here...',
      'v0.8.0',
      true
    );
    console.log('Verification:', verification.verified);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import hashlib
from typing import Dict, List, Optional

class TronContractAnalyzer:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def get_contract(self, contract_address: str) -> Dict:
        """Get raw contract data"""
        url = f"{self.base_url}/wallet/getcontract"
        
        payload = {
            "value": contract_address,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def get_contract_info(self, contract_address: str) -> Dict:
        """Get comprehensive contract information"""
        try:
            contract = self.get_contract(contract_address)
            
            if not contract.get('bytecode'):
                return {
                    'exists': False,
                    'address': contract_address,
                    'message': 'Contract not found or not deployed'
                }
            
            abi = self._parse_abi(contract.get('abi'))
            
            return {
                'exists': True,
                'address': contract_address,
                'bytecode': contract.get('bytecode'),
                'code_hash': contract.get('code_hash'),
                'creator': contract.get('origin_address'),
                'energy_limit': contract.get('origin_energy_limit', 0),
                'name': contract.get('name', 'Unknown'),
                'abi': abi,
                'is_verified': bool(contract.get('abi')),
                'functions': self._extract_functions(abi),
                'events': self._extract_events(abi),
                'analysis': self._analyze_contract(contract)
            }
        except Exception as e:
            print(f"Error getting contract info: {e}")
            raise
    
    def _parse_abi(self, abi_string) -> Optional[List]:
        """Parse ABI string to JSON"""
        if not abi_string:
            return None
        
        try:
            if isinstance(abi_string, str):
                return json.loads(abi_string)
            return abi_string
        except json.JSONDecodeError:
            print("Failed to parse ABI")
            return None
    
    def _extract_functions(self, abi: Optional[List]) -> List[Dict]:
        """Extract function information from ABI"""
        if not abi or not isinstance(abi, list):
            return []
        
        functions = []
        for item in abi:
            if item.get('type') == 'function':
                functions.append({
                    'name': item.get('name'),
                    'type': item.get('stateMutability', 'nonpayable'),
                    'inputs': item.get('inputs', []),
                    'outputs': item.get('outputs', []),
                    'signature': self._build_function_signature(item),
                    'is_view': item.get('stateMutability') in ['view', 'pure'],
                    'is_payable': item.get('stateMutability') == 'payable'
                })
        
        return functions
    
    def _extract_events(self, abi: Optional[List]) -> List[Dict]:
        """Extract event information from ABI"""
        if not abi or not isinstance(abi, list):
            return []
        
        events = []
        for item in abi:
            if item.get('type') == 'event':
                events.append({
                    'name': item.get('name'),
                    'inputs': item.get('inputs', []),
                    'signature': self._build_event_signature(item),
                    'anonymous': item.get('anonymous', False)
                })
        
        return events
    
    def _build_function_signature(self, func: Dict) -> str:
        """Build function signature string"""
        inputs = [inp.get('type', '') for inp in func.get('inputs', [])]
        return f"{func.get('name', '')}({','.join(inputs)})"
    
    def _build_event_signature(self, event: Dict) -> str:
        """Build event signature string"""
        inputs = [inp.get('type', '') for inp in event.get('inputs', [])]
        return f"{event.get('name', '')}({','.join(inputs)})"
    
    def _analyze_contract(self, contract: Dict) -> Dict:
        """Analyze contract features and patterns"""
        bytecode = contract.get('bytecode', '')
        abi = self._parse_abi(contract.get('abi'))
        
        analysis = {
            'bytecode_size': len(bytecode) // 2 if bytecode else 0,
            'has_constructor': False,
            'has_fallback': False,
            'has_receive': False,
            'function_count': 0,
            'event_count': 0,
            'has_payable_functions': False,
            'is_proxy': self._detect_proxy(bytecode, abi),
            'is_token': self._detect_token_standard(abi),
            'security_flags': self._analyze_security_features(abi)
        }
        
        if abi:
            analysis.update({
                'has_constructor': any(item.get('type') == 'constructor' for item in abi),
                'has_fallback': any(item.get('type') == 'fallback' for item in abi),
                'has_receive': any(item.get('type') == 'receive' for item in abi),
                'function_count': len([item for item in abi if item.get('type') == 'function']),
                'event_count': len([item for item in abi if item.get('type') == 'event']),
                'has_payable_functions': any(
                    item.get('type') == 'function' and item.get('stateMutability') == 'payable' 
                    for item in abi
                )
            })
        
        return analysis
    
    def _detect_proxy(self, bytecode: str, abi: Optional[List]) -> bool:
        """Detect if contract is a proxy"""
        if not bytecode:
            return False
        
        # Simplified proxy detection
        proxy_patterns = [
            '3660006000376110006000366000f3',  # Minimal proxy pattern
            'delegatecall'  # Contains delegate call
        ]
        
        return any(pattern.lower() in bytecode.lower() for pattern in proxy_patterns)
    
    def _detect_token_standard(self, abi: Optional[List]) -> Optional[str]:
        """Detect token standard (TRC20, TRC721, etc.)"""
        if not abi or not isinstance(abi, list):
            return None
        
        functions = [item.get('name') for item in abi if item.get('type') == 'function']
        events = [item.get('name') for item in abi if item.get('type') == 'event']
        
        # Check for TRC20 standard
        trc20_functions = ['totalSupply', 'balanceOf', 'transfer', 'transferFrom', 'approve', 'allowance']
        trc20_events = ['Transfer', 'Approval']
        
        has_trc20_functions = all(func in functions for func in trc20_functions)
        has_trc20_events = all(event in events for event in trc20_events)
        
        if has_trc20_functions and has_trc20_events:
            return 'TRC20'
        
        # Check for TRC721 standard
        trc721_functions = ['balanceOf', 'ownerOf', 'approve', 'getApproved', 'setApprovalForAll', 'isApprovedForAll', 'transferFrom', 'safeTransferFrom']
        has_trc721_functions = all(func in functions for func in trc721_functions)
        
        if has_trc721_functions:
            return 'TRC721'
        
        return None
    
    def _analyze_security_features(self, abi: Optional[List]) -> List[str]:
        """Analyze security features and patterns"""
        if not abi or not isinstance(abi, list):
            return []
        
        flags = []
        functions = [item for item in abi if item.get('type') == 'function']
        function_names = [func.get('name', '').lower() for func in functions]
        
        # Check for common security patterns
        if any('owner' in name for name in function_names):
            flags.append('Ownable')
        
        if any('pause' in name or 'emergency' in name for name in function_names):
            flags.append('Pausable')
        
        if any('upgrade' in name for name in function_names):
            flags.append('Upgradeable')
        
        if any('timelock' in name for name in function_names):
            flags.append('Timelock')
        
        return flags

class TronContractVerifier:
    def __init__(self, api_key: str):
        self.analyzer = TronContractAnalyzer(api_key)
    
    def verify_contract(self, contract_address: str, source_code: str, 
                       compiler_version: str, optimized: bool = False) -> Dict:
        """Verify contract against source code"""
        try:
            contract_info = self.analyzer.get_contract_info(contract_address)
            
            if not contract_info['exists']:
                return {
                    'verified': False,
                    'reason': 'Contract not found on blockchain'
                }
            
            # Simplified verification - in reality you'd compile the source
            verification = self._simulate_verification(
                contract_info['bytecode'],
                source_code,
                compiler_version,
                optimized
            )
            
            return {
                'verified': verification['matches'],
                'contract_info': contract_info,
                'verification': {
                    'source_bytecode_hash': verification['source_hash'],
                    'deployed_bytecode_hash': contract_info['code_hash'],
                    'matches': verification['matches'],
                    'compiler_version': compiler_version,
                    'optimized': optimized
                },
                'reason': 'Contract verified successfully' if verification['matches'] else 'Bytecode mismatch'
            }
            
        except Exception as e:
            return {
                'verified': False,
                'reason': f'Verification error: {str(e)}'
            }
    
    def _simulate_verification(self, deployed_bytecode: str, source_code: str, 
                              compiler_version: str, optimized: bool) -> Dict:
        """Simulate verification process"""
        # In reality, this would:
        # 1. Compile source code with specified compiler and settings
        # 2. Compare resulting bytecode with deployed bytecode
        # 3. Handle constructor arguments and library linking
        
        source_hash = hashlib.sha256(source_code.encode()).hexdigest()
        deployed_hash = hashlib.sha256(deployed_bytecode.encode()).hexdigest()
        
        return {
            'matches': False,  # Would be True if bytecode matches
            'source_hash': source_hash,
            'deployed_hash': deployed_hash
        }

# Usage examples
if __name__ == "__main__":
    analyzer = TronContractAnalyzer('YOUR_API_KEY')
    
    try:
        # USDT TRC20 contract
        usdt_contract = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
        
        # Get contract information
        contract_info = analyzer.get_contract_info(usdt_contract)
        
        print("Contract Analysis:")
        print(f"  Name: {contract_info['name']}")
        print(f"  Exists: {contract_info['exists']}")
        print(f"  Verified: {contract_info['is_verified']}")
        print(f"  Token Standard: {contract_info['analysis']['is_token']}")
        print(f"  Function Count: {contract_info['analysis']['function_count']}")
        print(f"  Event Count: {contract_info['analysis']['event_count']}")
        print(f"  Bytecode Size: {contract_info['analysis']['bytecode_size']} bytes")
        print(f"  Security Features: {contract_info['analysis']['security_flags']}")
        
        # Show some functions
        if contract_info['functions']:
            print(f"\nSample Functions:")
            for func in contract_info['functions'][:5]:
                print(f"  {func['signature']} ({'view' if func['is_view'] else 'write'})")
        
        # Contract verification example
        verifier = TronContractVerifier('YOUR_API_KEY')
        verification = verifier.verify_contract(
            usdt_contract,
            "// Contract source code would go here",
            "v0.8.0",
            True
        )
        
        print(f"\nVerification Result: {verification['verified']}")
        print(f"Reason: {verification['reason']}")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Verified Contract (USDT)

```json
{
  "bytecode": "608060405234801561001057600080fd5b50600436106101735760003560e01c80636a...",
  "name": "TetherToken",
  "abi": "[{\"inputs\":[{\"name\":\"_initialSupply\",\"type\":\"uint256\"}],\"name\":\"constructor\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]",
  "origin_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
  "origin_energy_limit": 10000000,
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "code_hash": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
}
```

### Unverified Contract

```json
{
  "bytecode": "608060405234801561001057600080fd5b506004361061017357600035...",
  "origin_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
  "origin_energy_limit": 5000000,
  "contract_address": "TAbCdEfGhIjKlMnOpQrStUvWxYz123456789",
  "code_hash": "b2c3d4e5f6789012345678901234567890123456789012345678901234567890a1"
}
```

### Contract Not Found

```json
{}
```

## Common Use Cases

### 1. Contract Explorer

```javascript
class TronContractExplorer {
  constructor(apiKey) {
    this.analyzer = new TronContractAnalyzer(apiKey);
  }
  
  async exploreContract(contractAddress) {
    try {
      const contractInfo = await this.analyzer.getContractInfo(contractAddress);
      
      if (!contractInfo.exists) {
        return { error: 'Contract not found' };
      }
      
      return {
        basicInfo: {
          address: contractInfo.address,
          name: contractInfo.name,
          creator: contractInfo.creator,
          isVerified: contractInfo.isVerified,
          standard: contractInfo.analysis.isToken
        },
        codeInfo: {
          bytecodeSize: contractInfo.analysis.bytecodeSize,
          codeHash: contractInfo.codeHash,
          hasProxy: contractInfo.analysis.isProxy
        },
        interface: {
          functionCount: contractInfo.analysis.functionCount,
          eventCount: contractInfo.analysis.eventCount,
          viewFunctions: contractInfo.functions.filter(f => f.isView).length,
          writeFunctions: contractInfo.functions.filter(f => !f.isView).length,
          payableFunctions: contractInfo.functions.filter(f => f.isPayable).length
        },
        security: {
          features: contractInfo.analysis.securityFlags,
          hasPayableFunctions: contractInfo.analysis.hasPayableFunctions,
          hasConstructor: contractInfo.analysis.hasConstructor
        }
      };
    } catch (error) {
      return { error: error.message };
    }
  }
}
```

## Performance Tips

1. **Cache Contract Data** - Contract information rarely changes, cache for hours
2. **Batch Requests** - Check multiple contracts efficiently
3. **ABI Parsing** - Parse and cache ABI data for reuse
4. **Selective Loading** - Only fetch detailed analysis when needed

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/getcontractinfo - Get Contract Details

# wallet/getcontractinfo - Get Contract Details

Get detailed information about a deployed smart contract.

## Endpoint

```
POST /wallet/getcontractinfo
```

## Request Parameters

- `value` (`string, required`): Required parameter: Contract address (base58 or hex)
- `visible` (`boolean, required`): Optional parameter: Return base58 addresses (default: false returns hex)

## Request Example

```bash
# Get contract info with visible address
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo \
      -H "Content-Type: application/json" \
      -d '{
        "value": "TContractAddress...",
        "visible": true
      }'

    # Get contract info with hex address
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo \
      -H "Content-Type: application/json" \
      -d '{
        "value": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c"
      }'

    # Extract ABI using jq
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo \
      -H "Content-Type: application/json" \
      -d '{
        "value": "TContractAddress...",
        "visible": true
      }' | jq '.abi.entrys[] | select(.type == "Function") | .name'
```

## Response Fields

- `result` (`OBJECT, required`): `contract_address` - Contract address `contract_name` - Contract name `abi` - Contract ABI (Application Binary Interface) `entrys` - Array of contract functions and events `bytecode` - Compiled contract bytecode `consumed_energy` - Total energy consumed by contract `origin_energy_limit` - Original energy limit `origin_address` - Contract creator address `trx_hash` - Transaction hash of contract creation

## Successful Response

```json
{
  "contract_address": "TContractAddress...",
  "contract_name": "MyToken",
  "abi": {
    "entrys": [
      {
        "name": "transfer",
        "inputs": [
          {
            "name": "to",
            "type": "address"
          },
          {
            "name": "amount",
            "type": "uint256"
          }
        ],
        "outputs": [
          {
            "type": "bool"
          }
        ],
        "type": "Function",
        "stateMutability": "nonpayable"
      },
      {
        "name": "Transfer",
        "inputs": [
          {
            "indexed": true,
            "name": "from",
            "type": "address"
          },
          {
            "indexed": true,
            "name": "to",
            "type": "address"
          },
          {
            "indexed": false,
            "name": "value",
            "type": "uint256"
          }
        ],
        "type": "Event"
      },
      {
        "name": "balanceOf",
        "inputs": [
          {
            "name": "account",
            "type": "address"
          }
        ],
        "outputs": [
          {
            "type": "uint256"
          }
        ],
        "type": "Function",
        "stateMutability": "view"
      }
    ]
  },
  "bytecode": "608060405234801561001057600080fd5b50...",
  "consumed_energy": 125430000,
  "origin_energy_limit": 10000000,
  "origin_address": "TCreatorAddress...",
  "trx_hash": "7c2d4206c03a883dd9066d6c839d0deaef32dc5a0d9b15f6d06e506906c90332"
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get contract info with visible address
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TContractAddress...",
    "visible": true
  }'

# Get contract info with hex address
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo \
  -H "Content-Type: application/json" \
  -d '{
    "value": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c"
  }'

# Extract ABI using jq
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TContractAddress...",
    "visible": true
  }' | jq '.abi.entrys[] | select(.type == "Function") | .name'
```

```javascript
// Get contract information
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    value: 'TContractAddress...',
    visible: true
  }),
});

const contract = await response.json();

// Parse ABI
if (contract.abi && contract.abi.entrys) {
  console.log('Contract Functions:');
  contract.abi.entrys.forEach(entry => {
    if (entry.type === 'Function') {
      const inputs = entry.inputs ? entry.inputs.map(i => `${i.type} ${i.name}`).join(', ') : '';
      const outputs = entry.outputs ? entry.outputs.map(o => o.type).join(', ') : 'void';
      console.log(`  ${entry.name}(${inputs}) returns (${outputs})`);
    }
  });
  
  console.log('\nContract Events:');
  contract.abi.entrys.forEach(entry => {
    if (entry.type === 'Event') {
      const params = entry.inputs ? entry.inputs.map(i => `${i.type} ${i.indexed ? 'indexed ' : ''}${i.name}`).join(', ') : '';
      console.log(`  ${entry.name}(${params})`);
    }
  });
}

// Display contract stats
console.log('\nContract Statistics:');
console.log(`Creator: ${contract.origin_address}`);
console.log(`Energy Consumed: ${contract.consumed_energy}`);
console.log(`Creation TX: ${contract.trx_hash}`);
```

```python
import requests
import json

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getcontractinfo"

payload = {
    "value": "TContractAddress...",
    "visible": True
}

response = requests.post(url, json=payload)
contract = response.json()

# Check if contract exists
if 'Error' in contract:
    print(f"Contract not found: {contract['Error']}")
else:
    print(f"Contract: {contract.get('contract_name', 'Unknown')}")
    print(f"Address: {contract.get('contract_address', '')}")
    print(f"Creator: {contract.get('origin_address', '')}")
    
    # Parse ABI
    if 'abi' in contract and 'entrys' in contract['abi']:
        functions = [e for e in contract['abi']['entrys'] if e.get('type') == 'Function']
        events = [e for e in contract['abi']['entrys'] if e.get('type') == 'Event']
        
        print(f"\nFunctions ({len(functions)}):")
        for func in functions:
            inputs = ', '.join([f"{i['type']} {i['name']}" for i in func.get('inputs', [])])
            outputs = ', '.join([o['type'] for o in func.get('outputs', [])])
            print(f"  - {func['name']}({inputs})")
            if outputs:
                print(f"    Returns: {outputs}")
        
        print(f"\nEvents ({len(events)}):")
        for event in events:
            params = ', '.join([
                f"{'indexed ' if i.get('indexed') else ''}{i['type']} {i['name']}" 
                for i in event.get('inputs', [])
            ])
            print(f"  - {event['name']}({params})")
    
    # Display energy consumption
    if 'consumed_energy' in contract:
        energy_in_trx = contract['consumed_energy'] * 420 / 1_000_000  # Energy price ~420 SUN
        print(f"\nTotal Energy Consumed: {contract['consumed_energy']:,}")
        print(f"Estimated Cost: {energy_in_trx:.2f} TRX")
```

## ABI Entry Types

### Function Entry

```json
{
  "name": "functionName",
  "inputs": [...],
  "outputs": [...],
  "type": "Function",
  "stateMutability": "view|pure|nonpayable|payable"
}
```

### Event Entry

```json
{
  "name": "EventName",
  "inputs": [
    {
      "indexed": true,
      "name": "param1",
      "type": "address"
    }
  ],
  "type": "Event"
}
```

### Constructor Entry

```json
{
  "inputs": [...],
  "type": "Constructor",
  "stateMutability": "nonpayable"
}
```

## Contract Verification

```javascript
// Verify contract source code matches deployed bytecode
async function verifyContract(address, sourceCode, compilerVersion) {
  // Get deployed contract info
  const response = await fetch(`${API_URL}/wallet/getcontractinfo`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ value: address, visible: true })
  });
  
  const contract = await response.json();
  const deployedBytecode = contract.bytecode;
  
  // Compile source code (pseudo-code)
  const compiledBytecode = await compileContract(sourceCode, compilerVersion);
  
  // Compare bytecodes (excluding metadata)
  const verified = compareBytecode(deployedBytecode, compiledBytecode);
  
  return {
    verified,
    contractName: contract.contract_name,
    abi: contract.abi,
    creator: contract.origin_address
  };
}
```

## Best Practices

### 1. **Cache Contract Info**

- ABI doesn't change after deployment
- Cache to reduce API calls
- Update cache only when needed

### 2. **Validate Contracts**

- Check bytecode exists
- Verify ABI structure
- Confirm expected functions present

### 3. **Energy Monitoring**

- Track consumed\_energy growth
- Monitor for unusual consumption
- Alert on high energy usage

## Common Errors

| Error                                            | Description               | Solution                  |
| ------------------------------------------------ | ------------------------- | ------------------------- |
| `Contract does not exist`                        | Invalid contract address  | Verify address is correct |
| `Not a smart contract address`                   | Address is not a contract | Check address type first  |
| `class org.tron.core.exception.BadItemException` | Malformed request         | Check parameter format    |

## Use Cases

- **Contract Verification**: Verify deployed contract matches source
- **ABI Extraction**: Get contract interface for interaction
- **DApp Integration**: Load contract details dynamically
- **Analytics**: Track contract usage and energy consumption
- **Security Auditing**: Analyze contract bytecode and functions

## Related Methods

- [wallet/triggersmartcontract](https://www.dwellir.com/docs/tron/wallet-triggersmartcontract) - Call contract function
- [wallet/triggerconstantcontract](https://www.dwellir.com/docs/tron/wallet-triggerconstantcontract) - Call view function
- [wallet/estimateenergy](https://www.dwellir.com/docs/tron/wallet-estimateenergy) - Estimate energy for call

---

## wallet/getnodeinfo - Get TRON Node Information

# wallet/getnodeinfo - Get TRON Node Information

**Dwellir's TRON infrastructure** provides instant node status with version info, sync state, and network connectivity.
Monitor node health and configuration for optimal integration.

[Access node information](https://dashboard.dwellir.com/register)

Retrieve detailed information about the connected TRON node including software version, network configuration, current block height, and peer connections.

## Use Cases

`wallet/getnodeinfo` is crucial for:

- **Health Monitoring** - Check node status and sync state
- **Version Tracking** - Verify node software version
- **Network Analysis** - Monitor peer connections
- **Configuration Audit** - Review node settings
- **Debugging** - Troubleshoot connection issues

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{}
```

## Response Fields

- `beginSyncNum` (`number, required`): Block number when sync started
- `block` (`string, required`): Current block hash and height
- `solidityBlock` (`string, required`): Latest solidified block
- `currentConnectCount` (`number, required`): Current peer connections
- `activeConnectCount` (`number, required`): Active peer connections
- `passiveConnectCount` (`number, required`): Passive peer connections
- `totalFlow` (`number, required`): Total network traffic
- `peerList` (`array, required`): Connected peer information
- `configNodeInfo` (`object, required`): Node configuration details
- `machineInfo` (`object, required`): Hardware and OS information
- `cheatWitnessInfoMap` (`object, required`): Witness validation info

## Successful Response

```json
{
  "beginSyncNum": 58000000,
  "block": "Num:58234567,ID:0000000003787ac74d9bb8f8c9c59ac3f3e3b9b8c9e3e8f9",
  "solidityBlock": "Num:58234547,ID:0000000003787ab34d9bb8f8c9c59ac3f3e3b9b8c9e3e8f8",
  "currentConnectCount": 30,
  "activeConnectCount": 18,
  "passiveConnectCount": 12,
  "totalFlow": 1234567890,
  "peerList": [
    {
      "host": "192.168.1.100",
      "port": 18888,
      "avgLatency": 45,
      "blockInNum": 58234567,
      "connectTime": 1702456789000,
      "nodeInfo": {
        "codeVersion": "4.7.2",
        "p2pVersion": "1.0.0"
      }
    }
  ],
  "configNodeInfo": {
    "codeVersion": "4.7.2",
    "versionName": "GreatVoyage-v4.7.2",
    "versionNum": "17766",
    "p2pVersion": "11111",
    "listenPort": 18888,
    "discoverEnable": true,
    "activeNodeSize": 18,
    "passiveNodeSize": 12,
    "sendNodeSize": 30,
    "maxConnectCount": 50,
    "sameIpMaxConnectCount": 2,
    "backupListenPort": 10001,
    "backupMemberSize": 0,
    "backupPriority": 8,
    "dbVersion": 2,
    "minParticipationRate": 15,
    "supportConstant": true,
    "minTimeRatio": 0.6,
    "maxTimeRatio": 5.0,
    "allowCreationOfContracts": 0,
    "allowAdaptiveEnergy": 0
  },
  "machineInfo": {
    "threadCount": 150,
    "deadLockThreadCount": 0,
    "cpuCount": 16,
    "totalMemory": 34359738368,
    "freeMemory": 12884901888,
    "cpuRate": 0.35,
    "javaVersion": "1.8.0_292",
    "osName": "Linux",
    "jvmTotalMemory": 8589934592,
    "jvmFreeMemory": 4294967296,
    "processCpuRate": 0.25,
    "memoryDescInfo": "Total: 32GB, Free: 12GB, Usage: 62.5%",
    "deadLockThreadInfoList": []
  },
  "cheatWitnessInfoMap": {}
}
```

## Error Responses

### Error 1

- Description: Block number when sync started

### Error 2

- Description: Current block hash and height

### Error 3

- Description: Latest solidified block

### Error 4

- Description: Current peer connections

### Error 5

- Description: Active peer connections

### Error 6

- Description: Passive peer connections

### Error 7

- Description: Total network traffic

### Error 8

- Description: Connected peer information

### Error 9

- Description: Node configuration details

### Error 10

- Description: Hardware and OS information

### Error 11

- Description: Witness validation info

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get node information
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnodeinfo" \
  -H "Content-Type: application/json" \
  -d '{}'

# Parse basic info with jq
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnodeinfo" \
  -H "Content-Type: application/json" \
  -d '{}' | jq '{
    version: .configNodeInfo.codeVersion,
    network: .configNodeInfo.network,
    current_block: .block,
    solidity_block: .solidityBlock,
    peers: .currentConnectCount,
    active_peers: .activeConnectCount
  }'

# Get sync status
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnodeinfo" \
  -H "Content-Type: application/json" \
  -d '{}' | jq '{
    current: (.block | split(",")[0] | split(":")[1] | tonumber),
    solidity: (.solidityBlock | split(",")[0] | split(":")[1] | tonumber),
    lag: ((.block | split(",")[0] | split(":")[1] | tonumber) - 
          (.solidityBlock | split(",")[0] | split(":")[1] | tonumber))
  }'

# Monitor node status script
#!/bin/bash
API_KEY="YOUR_API_KEY"

while true; do
  echo "=== TRON Node Status - $(date) ==="
  
  response=$(curl -s -X POST \
    "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/getnodeinfo" \
    -H "Content-Type: application/json" \
    -d '{}')
  
  if [ $? -eq 0 ]; then
    echo "✓ Node Online"
    echo "$response" | jq -r '
      "Version: " + .configNodeInfo.codeVersion,
      "Network: " + .configNodeInfo.network,
      "Peers: " + (.currentConnectCount | tostring),
      "Block: " + .block
    '
  else
    echo "✗ Node Offline"
  fi
  
  echo ""
  sleep 30
done

# Extract peer information
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnodeinfo" \
  -H "Content-Type: application/json" \
  -d '{}' | jq '
  {
    peer_count: .peerList | length,
    top_peers: [.peerList[] | {
      host: .host,
      port: .port,
      version: .nodeInfo.codeVersion,
      latency: .avgLatency
    }] | sort_by(.latency) | .[0:5]
  }'
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get basic node information
async function getNodeInfo() {
  const response = await fetch(`${TRON_API}/wallet/getnodeinfo`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({})
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  return await response.json();
}

// Comprehensive node monitor
class TronNodeMonitor {
  constructor(apiKey) {
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
    this.lastInfo = null;
    this.alerts = [];
  }
  
  async fetchNodeInfo() {
    const response = await fetch(`${this.apiUrl}/wallet/getnodeinfo`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({})
    });
    
    if (!response.ok) {
      throw new Error(`Node info request failed: ${response.statusText}`);
    }
    
    return await response.json();
  }
  
  async getStatus() {
    try {
      const info = await this.fetchNodeInfo();
      
      // Parse block information
      const blockInfo = this.parseBlockInfo(info.block);
      const solidityBlockInfo = this.parseBlockInfo(info.solidityBlock);
      
      // Calculate sync status
      const syncLag = blockInfo.number - solidityBlockInfo.number;
      const isSynced = syncLag < 100; // Consider synced if less than 100 blocks behind
      
      return {
        online: true,
        version: info.configNodeInfo?.codeVersion || 'Unknown',
        network: info.configNodeInfo?.network || 'mainnet',
        currentBlock: blockInfo.number,
        solidityBlock: solidityBlockInfo.number,
        syncLag: syncLag,
        isSynced: isSynced,
        peers: {
          total: info.currentConnectCount || 0,
          active: info.activeConnectCount || 0,
          passive: info.passiveConnectCount || 0
        },
        traffic: this.formatBytes(info.totalFlow || 0),
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      return {
        online: false,
        error: error.message,
        timestamp: new Date().toISOString()
      };
    }
  }
  
  parseBlockInfo(blockString) {
    if (!blockString) return { hash: null, number: 0 };
    
    // Format: "Num:12345,ID:hash"
    const parts = blockString.split(',');
    const num = parts[0]?.split(':')[1] || '0';
    const id = parts[1]?.split(':')[1] || '';
    
    return {
      number: parseInt(num, 10),
      hash: id
    };
  }
  
  async getDetailedInfo() {
    const info = await this.fetchNodeInfo();
    
    return {
      basic: {
        version: info.configNodeInfo?.codeVersion,
        network: info.configNodeInfo?.network,
        dbVersion: info.configNodeInfo?.dbVersion,
        p2pVersion: info.configNodeInfo?.p2pVersion
      },
      sync: {
        beginBlock: info.beginSyncNum,
        currentBlock: this.parseBlockInfo(info.block).number,
        solidityBlock: this.parseBlockInfo(info.solidityBlock).number,
        needSync: info.needSync
      },
      network: {
        listenPort: info.configNodeInfo?.listenPort,
        discoveryEnabled: info.configNodeInfo?.discoverEnabled,
        activeNodes: info.configNodeInfo?.activeNodeSize,
        passiveNodes: info.configNodeInfo?.passiveNodeSize,
        maxConnections: info.configNodeInfo?.maxConnectCount
      },
      peers: this.analyzePeers(info.peerList || []),
      machine: {
        cpuCount: info.machineInfo?.cpuCount,
        cpuRate: info.machineInfo?.cpuRate,
        memoryUsage: info.machineInfo?.memoryDescInfo,
        javaVersion: info.machineInfo?.javaVersion,
        osName: info.machineInfo?.osName,
        totalMemory: info.machineInfo?.totalMemory,
        freeMemory: info.machineInfo?.freeMemory
      }
    };
  }
  
  analyzePeers(peerList) {
    const analysis = {
      total: peerList.length,
      byVersion: {},
      byCountry: {},
      avgLatency: 0,
      topPeers: []
    };
    
    let totalLatency = 0;
    
    peerList.forEach(peer => {
      // Count by version
      const version = peer.nodeInfo?.codeVersion || 'Unknown';
      analysis.byVersion[version] = (analysis.byVersion[version] || 0) + 1;
      
      // Track latency
      if (peer.avgLatency) {
        totalLatency += peer.avgLatency;
      }
      
      // Add to top peers
      analysis.topPeers.push({
        address: peer.host,
        port: peer.port,
        latency: peer.avgLatency,
        version: version,
        blockHeight: peer.blockInNum,
        connected: peer.connectTime
      });
    });
    
    // Calculate average latency
    if (peerList.length > 0) {
      analysis.avgLatency = Math.round(totalLatency / peerList.length);
    }
    
    // Sort top peers by block height
    analysis.topPeers.sort((a, b) => b.blockHeight - a.blockHeight);
    analysis.topPeers = analysis.topPeers.slice(0, 10);
    
    return analysis;
  }
  
  async monitorHealth(intervalMs = 60000) {
    const checkHealth = async () => {
      const status = await this.getStatus();
      
      // Check for issues
      if (!status.online) {
        this.addAlert('error', 'Node is offline', status);
      } else if (!status.isSynced) {
        this.addAlert('warning', `Node is ${status.syncLag} blocks behind`, status);
      } else if (status.peers.total < 5) {
        this.addAlert('warning', `Low peer count: ${status.peers.total}`, status);
      }
      
      this.lastInfo = status;
      return status;
    };
    
    // Initial check
    await checkHealth();
    
    // Set up monitoring interval
    return setInterval(checkHealth, intervalMs);
  }
  
  addAlert(level, message, data) {
    const alert = {
      level,
      message,
      data,
      timestamp: new Date().toISOString()
    };
    
    this.alerts.push(alert);
    
    // Keep only last 100 alerts
    if (this.alerts.length > 100) {
      this.alerts = this.alerts.slice(-100);
    }
    
    // Trigger alert handler if configured
    this.onAlert?.(alert);
  }
  
  getAlerts(level = null) {
    if (level) {
      return this.alerts.filter(a => a.level === level);
    }
    return this.alerts;
  }
  
  formatBytes(bytes) {
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    if (bytes === 0) return '0 B';
    const i = Math.floor(Math.log(bytes) / Math.log(1024));
    return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
  }
}

// Dashboard component
class NodeDashboard {
  constructor(apiKey) {
    this.monitor = new TronNodeMonitor(apiKey);
    this.updateInterval = null;
  }
  
  async start(elementId, refreshInterval = 30000) {
    const container = document.getElementById(elementId);
    if (!container) return;
    
    const update = async () => {
      const status = await this.monitor.getStatus();
      container.innerHTML = this.renderDashboard(status);
    };
    
    // Initial render
    await update();
    
    // Set up auto-refresh
    this.updateInterval = setInterval(update, refreshInterval);
  }
  
  renderDashboard(status) {
    if (!status.online) {
      return `
        <div class="node-dashboard error">
          <h3>⚠️ Node Offline</h3>
          <p>Error: ${status.error}</p>
          <p>Last check: ${status.timestamp}</p>
        </div>
      `;
    }
    
    const syncStatus = status.isSynced ? 
      '<span class="badge success">Synced</span>' : 
      `<span class="badge warning">Syncing (${status.syncLag} blocks behind)</span>`;
    
    return `
      <div class="node-dashboard">
        <h3>TRON Node Status</h3>
        <div class="status-grid">
          <div class="status-item">
            <label>Version:</label>
            <span>${status.version}</span>
          </div>
          <div class="status-item">
            <label>Network:</label>
            <span>${status.network}</span>
          </div>
          <div class="status-item">
            <label>Current Block:</label>
            <span>${status.currentBlock.toLocaleString()}</span>
          </div>
          <div class="status-item">
            <label>Sync Status:</label>
            ${syncStatus}
          </div>
          <div class="status-item">
            <label>Peers:</label>
            <span>${status.peers.total} (${status.peers.active} active)</span>
          </div>
          <div class="status-item">
            <label>Traffic:</label>
            <span>${status.traffic}</span>
          </div>
        </div>
        <p class="updated">Updated: ${new Date(status.timestamp).toLocaleTimeString()}</p>
      </div>
    `;
  }
  
  stop() {
    if (this.updateInterval) {
      clearInterval(this.updateInterval);
      this.updateInterval = null;
    }
  }
}

// Usage examples
(async () => {
  const monitor = new TronNodeMonitor('YOUR_API_KEY');
  
  try {
    // Get basic status
    const status = await monitor.getStatus();
    console.log('Node Status:', status);
    
    // Get detailed information
    const detailed = await monitor.getDetailedInfo();
    console.log('Detailed Info:', detailed);
    
    // Set up health monitoring
    monitor.onAlert = (alert) => {
      console.log(`[${alert.level.toUpperCase()}] ${alert.message}`);
    };
    
    const monitorHandle = await monitor.monitorHealth(60000);
    
    // Start dashboard (if in browser)
    if (typeof document !== 'undefined') {
      const dashboard = new NodeDashboard('YOUR_API_KEY');
      await dashboard.start('node-status', 30000);
    }
    
    // Stop monitoring after 5 minutes
    setTimeout(() => {
      clearInterval(monitorHandle);
      console.log('Monitoring stopped');
    }, 5 * 60 * 1000);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
from typing import Dict, List, Optional
from datetime import datetime
import time
from threading import Thread, Event

class TronNodeMonitor:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {'Content-Type': 'application/json'}
        self.last_info = None
        self.alerts = []
    
    def get_node_info(self) -> Dict:
        """
        Fetch raw node information
        """
        url = f"{self.base_url}/wallet/getnodeinfo"
        
        try:
            response = requests.post(url, headers=self.headers, json={})
            response.raise_for_status()
            return response.json()
        except requests.RequestException as e:
            raise Exception(f"Failed to get node info: {str(e)}")
    
    def get_status(self) -> Dict:
        """
        Get formatted node status
        """
        try:
            info = self.get_node_info()
            
            # Parse block information
            block_info = self._parse_block_info(info.get('block', ''))
            solidity_block_info = self._parse_block_info(info.get('solidityBlock', ''))
            
            # Calculate sync status
            sync_lag = block_info['number'] - solidity_block_info['number']
            is_synced = sync_lag < 100
            
            return {
                'online': True,
                'version': info.get('configNodeInfo', {}).get('codeVersion', 'Unknown'),
                'network': info.get('configNodeInfo', {}).get('network', 'mainnet'),
                'current_block': block_info['number'],
                'solidity_block': solidity_block_info['number'],
                'sync_lag': sync_lag,
                'is_synced': is_synced,
                'peers': {
                    'total': info.get('currentConnectCount', 0),
                    'active': info.get('activeConnectCount', 0),
                    'passive': info.get('passiveConnectCount', 0)
                },
                'traffic': self._format_bytes(info.get('totalFlow', 0)),
                'timestamp': datetime.now().isoformat()
            }
        except Exception as e:
            return {
                'online': False,
                'error': str(e),
                'timestamp': datetime.now().isoformat()
            }
    
    def _parse_block_info(self, block_string: str) -> Dict:
        """
        Parse block string format: 'Num:12345,ID:hash'
        """
        if not block_string:
            return {'hash': None, 'number': 0}
        
        parts = block_string.split(',')
        num = 0
        hash_id = ''
        
        for part in parts:
            if 'Num:' in part:
                num = int(part.split(':')[1])
            elif 'ID:' in part:
                hash_id = part.split(':')[1]
        
        return {'number': num, 'hash': hash_id}
    
    def get_detailed_info(self) -> Dict:
        """
        Get comprehensive node information
        """
        info = self.get_node_info()
        
        config = info.get('configNodeInfo', {})
        machine = info.get('machineInfo', {})
        
        return {
            'basic': {
                'version': config.get('codeVersion'),
                'network': config.get('network'),
                'db_version': config.get('dbVersion'),
                'p2p_version': config.get('p2pVersion'),
                'min_participation_rate': config.get('minParticipationRate'),
                'support_constant': config.get('supportConstant')
            },
            'sync': {
                'begin_block': info.get('beginSyncNum'),
                'current_block': self._parse_block_info(info.get('block', ''))['number'],
                'solidity_block': self._parse_block_info(info.get('solidityBlock', ''))['number'],
                'need_sync': info.get('needSync', False)
            },
            'network': {
                'listen_port': config.get('listenPort'),
                'discovery_enabled': config.get('discoverEnabled'),
                'active_nodes': config.get('activeNodeSize'),
                'passive_nodes': config.get('passiveNodeSize'),
                'max_connections': config.get('maxConnectCount'),
                'same_ip_max_count': config.get('sameIpMaxConnectCount'),
                'backup_priority': config.get('backupPriority')
            },
            'peers': self._analyze_peers(info.get('peerList', [])),
            'machine': {
                'cpu_count': machine.get('cpuCount'),
                'cpu_rate': machine.get('cpuRate'),
                'memory': machine.get('memoryDescInfo'),
                'java_version': machine.get('javaVersion'),
                'os_name': machine.get('osName'),
                'total_memory': machine.get('totalMemory'),
                'free_memory': machine.get('freeMemory'),
                'dead_lock_thread_count': machine.get('deadLockThreadCount')
            },
            'witnesses': self._analyze_witnesses(info.get('cheatWitnessInfoMap', {}))
        }
    
    def _analyze_peers(self, peer_list: List[Dict]) -> Dict:
        """
        Analyze peer connections
        """
        analysis = {
            'total': len(peer_list),
            'by_version': {},
            'avg_latency': 0,
            'top_peers': []
        }
        
        if not peer_list:
            return analysis
        
        total_latency = 0
        
        for peer in peer_list:
            # Count by version
            version = peer.get('nodeInfo', {}).get('codeVersion', 'Unknown')
            analysis['by_version'][version] = analysis['by_version'].get(version, 0) + 1
            
            # Track latency
            latency = peer.get('avgLatency', 0)
            total_latency += latency
            
            # Add to top peers
            analysis['top_peers'].append({
                'address': peer.get('host'),
                'port': peer.get('port'),
                'latency': latency,
                'version': version,
                'block_height': peer.get('blockInNum', 0),
                'connected_time': peer.get('connectTime')
            })
        
        # Calculate average latency
        analysis['avg_latency'] = round(total_latency / len(peer_list))
        
        # Sort and limit top peers
        analysis['top_peers'].sort(key=lambda x: x['block_height'], reverse=True)
        analysis['top_peers'] = analysis['top_peers'][:10]
        
        return analysis
    
    def _analyze_witnesses(self, witness_map: Dict) -> Dict:
        """
        Analyze witness information
        """
        if not witness_map:
            return {'total': 0, 'witnesses': []}
        
        witnesses = []
        for address, info in witness_map.items():
            witnesses.append({
                'address': address,
                'vote_count': info.get('voteCount', 0),
                'latest_block': info.get('latestBlockNum', 0)
            })
        
        witnesses.sort(key=lambda x: x['vote_count'], reverse=True)
        
        return {
            'total': len(witnesses),
            'witnesses': witnesses[:20]  # Top 20 witnesses
        }
    
    def monitor_health(self, check_interval: int = 60) -> Thread:
        """
        Start health monitoring in background thread
        """
        stop_event = Event()
        
        def monitor_loop():
            while not stop_event.is_set():
                status = self.get_status()
                
                # Check for issues
                if not status['online']:
                    self._add_alert('error', 'Node is offline', status)
                elif not status['is_synced']:
                    self._add_alert('warning', f"Node is {status['sync_lag']} blocks behind", status)
                elif status['peers']['total'] < 5:
                    self._add_alert('warning', f"Low peer count: {status['peers']['total']}", status)
                
                self.last_info = status
                stop_event.wait(check_interval)
        
        thread = Thread(target=monitor_loop, daemon=True)
        thread.stop_event = stop_event
        thread.start()
        return thread
    
    def _add_alert(self, level: str, message: str, data: Dict):
        """
        Add alert to list
        """
        alert = {
            'level': level,
            'message': message,
            'data': data,
            'timestamp': datetime.now().isoformat()
        }
        
        self.alerts.append(alert)
        
        # Keep only last 100 alerts
        if len(self.alerts) > 100:
            self.alerts = self.alerts[-100:]
    
    def get_alerts(self, level: Optional[str] = None) -> List[Dict]:
        """
        Get alerts, optionally filtered by level
        """
        if level:
            return [a for a in self.alerts if a['level'] == level]
        return self.alerts
    
    def _format_bytes(self, bytes_value: int) -> str:
        """
        Format bytes to human-readable string
        """
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if bytes_value < 1024.0:
                return f"{bytes_value:.2f} {unit}"
            bytes_value /= 1024.0
        return f"{bytes_value:.2f} PB"

class NodeStatusReporter:
    """
    Generate node status reports
    """
    def __init__(self, monitor: TronNodeMonitor):
        self.monitor = monitor
    
    def generate_report(self) -> str:
        """
        Generate comprehensive status report
        """
        status = self.monitor.get_status()
        detailed = self.monitor.get_detailed_info()
        
        report = []
        report.append("=" * 50)
        report.append("TRON Node Status Report")
        report.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        report.append("=" * 50)
        
        # Basic status
        report.append("\n[STATUS]")
        report.append(f"Online: {'✓' if status['online'] else '✗'}")
        if status['online']:
            report.append(f"Version: {status['version']}")
            report.append(f"Network: {status['network']}")
            report.append(f"Synced: {'✓' if status['is_synced'] else '✗'}")
            report.append(f"Current Block: {status['current_block']:,}")
            report.append(f"Solidity Block: {status['solidity_block']:,}")
            report.append(f"Sync Lag: {status['sync_lag']} blocks")
        else:
            report.append(f"Error: {status.get('error')}")
        
        # Network info
        report.append("\n[NETWORK]")
        report.append(f"Total Peers: {status['peers']['total']}")
        report.append(f"Active Peers: {status['peers']['active']}")
        report.append(f"Passive Peers: {status['peers']['passive']}")
        report.append(f"Network Traffic: {status['traffic']}")
        
        # Machine info
        if detailed['machine']['cpu_count']:
            report.append("\n[MACHINE]")
            report.append(f"CPU Count: {detailed['machine']['cpu_count']}")
            report.append(f"CPU Usage: {detailed['machine']['cpu_rate']}%")
            report.append(f"Memory: {detailed['machine']['memory']}")
            report.append(f"OS: {detailed['machine']['os_name']}")
        
        # Top peers
        if detailed['peers']['top_peers']:
            report.append("\n[TOP PEERS]")
            for peer in detailed['peers']['top_peers'][:5]:
                report.append(f"  - {peer['address']}:{peer['port']} "
                            f"(Block: {peer['block_height']:,}, "
                            f"Latency: {peer['latency']}ms)")
        
        # Recent alerts
        recent_alerts = self.monitor.get_alerts()[-5:]
        if recent_alerts:
            report.append("\n[RECENT ALERTS]")
            for alert in recent_alerts:
                report.append(f"  [{alert['level'].upper()}] {alert['message']}")
        
        report.append("\n" + "=" * 50)
        
        return "\n".join(report)

# Usage examples
if __name__ == "__main__":
    monitor = TronNodeMonitor('YOUR_API_KEY')
    reporter = NodeStatusReporter(monitor)
    
    try:
        # Get basic status
        print("Fetching node status...")
        status = monitor.get_status()
        
        if status['online']:
            print(f"✓ Node Online - Version {status['version']}")
            print(f"  Current Block: {status['current_block']:,}")
            print(f"  Sync Status: {'Synced' if status['is_synced'] else f'{status['sync_lag']} blocks behind'}")
            print(f"  Peers: {status['peers']['total']}")
        else:
            print(f"✗ Node Offline - {status['error']}")
        
        # Get detailed information
        print("\nFetching detailed information...")
        detailed = monitor.get_detailed_info()
        
        print(f"\nNetwork Configuration:")
        print(f"  Listen Port: {detailed['network']['listen_port']}")
        print(f"  Max Connections: {detailed['network']['max_connections']}")
        print(f"  Discovery Enabled: {detailed['network']['discovery_enabled']}")
        
        print(f"\nPeer Analysis:")
        print(f"  Total Peers: {detailed['peers']['total']}")
        print(f"  Average Latency: {detailed['peers']['avg_latency']}ms")
        print(f"  Version Distribution:")
        for version, count in detailed['peers']['by_version'].items():
            print(f"    {version}: {count} peers")
        
        # Generate full report
        print("\n" + reporter.generate_report())
        
        # Start monitoring (optional)
        print("\nStarting health monitoring (press Ctrl+C to stop)...")
        monitor_thread = monitor.monitor_health(30)
        
        try:
            while True:
                time.sleep(60)
                # Print any new alerts
                new_alerts = monitor.get_alerts()[-1:]
                for alert in new_alerts:
                    print(f"[{datetime.now().strftime('%H:%M:%S')}] "
                          f"[{alert['level'].upper()}] {alert['message']}")
        except KeyboardInterrupt:
            print("\nStopping monitor...")
            monitor_thread.stop_event.set()
            monitor_thread.join()
            
    except Exception as e:
        print(f"Error: {e}")
```

## Common Use Cases

### 1. Health Check Endpoint

```javascript
async function healthCheck() {
  try {
    const info = await getNodeInfo();
    const blockInfo = parseBlockString(info.block);
    const solidityInfo = parseBlockString(info.solidityBlock);
    
    const healthy = 
      info.currentConnectCount > 5 &&
      (blockInfo.number - solidityInfo.number) < 100;
    
    return {
      status: healthy ? 'healthy' : 'degraded',
      details: {
        peers: info.currentConnectCount,
        syncLag: blockInfo.number - solidityInfo.number,
        version: info.configNodeInfo?.codeVersion
      }
    };
  } catch (error) {
    return {
      status: 'unhealthy',
      error: error.message
    };
  }
}
```

### 2. Version Compatibility Check

```javascript
async function checkCompatibility(requiredVersion) {
  const info = await getNodeInfo();
  const nodeVersion = info.configNodeInfo?.codeVersion || '0.0.0';
  
  return {
    compatible: compareVersions(nodeVersion, requiredVersion) >= 0,
    nodeVersion,
    requiredVersion
  };
}
```

### 3. Network Statistics

```javascript
async function getNetworkStats() {
  const info = await getNodeInfo();
  
  // Analyze peer versions
  const versionStats = {};
  info.peerList?.forEach(peer => {
    const version = peer.nodeInfo?.codeVersion || 'Unknown';
    versionStats[version] = (versionStats[version] || 0) + 1;
  });
  
  return {
    totalPeers: info.currentConnectCount,
    activePeers: info.activeConnectCount,
    passivePeers: info.passiveConnectCount,
    versionDistribution: versionStats,
    networkTraffic: formatBytes(info.totalFlow)
  };
}
```

## Best Practices

1. **Cache Results** - Node info can be cached for 30-60 seconds
2. **Monitor Regularly** - Check node health every 1-5 minutes
3. **Alert Thresholds** - Set alerts for low peers or high sync lag
4. **Version Tracking** - Monitor node version for required updates
5. **Fallback Nodes** - Have backup nodes ready if health degrades

## Related Methods

- [wallet/getchainparameters](https://www.dwellir.com/docs/tron/wallet-getchainparameters) - Get chain configuration
- [wallet/getnowblock](https://www.dwellir.com/docs/tron/wallet-getnowblock) - Get latest block
- [wallet/listwitnesses](https://www.dwellir.com/docs/tron/wallet-listwitnesses) - Get witness list

***

*Need help? Contact [support](mailto:support@dwellir.com) or visit our [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/getnowblock - Get Current TRON Block

# wallet/getnowblock - Get Current TRON Block

**Dwellir's TRON endpoints** deliver the latest block information in under 20ms with 99.9% uptime.
Stay synchronized with TRON's 3-second block times for real-time applications.

[Get instant block data](https://dashboard.dwellir.com/register)

Retrieves the latest block information from the TRON network, including block number, timestamp, transactions, and block hash.

## When to Use This Method

`wallet/getnowblock` is essential for:

- **Real-Time Monitoring** - Track latest network activity and block production
- **Block Synchronization** - Keep applications synchronized with network state
- **Transaction Confirmation** - Monitor for transaction inclusion in new blocks
- **Network Health Monitoring** - Check block times and network performance
- **Block Explorer Development** - Display latest blocks and transactions

## Request Parameters

This method accepts no parameters.

## Request Example

```json
// No request body needed for this method
```

## Response Fields

- `result` (`OBJECT, required`): `blockID` - Unique block identifier (hash) `block_header` - Block header with metadata `transactions` - Array of transactions in the block `raw_data` - Raw block data `number` - Block number `txTrieRoot` - Transaction merkle root `witness_address` - Block producer address `parentHash` - Previous block hash `version` - Protocol version `timestamp` - Block timestamp in milliseconds `witness_signature` - Block producer signature

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get the latest block
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnowblock" \
  -H "Content-Type: application/json"

# Extract key information from latest block
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getnowblock" \
  -H "Content-Type: application/json" | jq '{
    block_number: .block_header.raw_data.number,
    block_hash: .blockID,
    timestamp: .block_header.raw_data.timestamp,
    datetime: (.block_header.raw_data.timestamp / 1000 | strftime("%Y-%m-%d %H:%M:%S")),
    transaction_count: (.transactions // [] | length),
    producer: .block_header.raw_data.witness_address
  }'

# Monitor for new blocks (bash script)
#!/bin/bash
API_KEY="YOUR_API_KEY"
LAST_BLOCK=0

echo "Starting TRON block monitor..."

while true; do
  # Get latest block
  RESPONSE=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/getnowblock" \
    -H "Content-Type: application/json")
  
  # Extract block number
  CURRENT_BLOCK=$(echo "$RESPONSE" | jq -r '.block_header.raw_data.number')
  
  if [ "$CURRENT_BLOCK" != "null" ] && [ "$CURRENT_BLOCK" -gt "$LAST_BLOCK" ]; then
    # Extract block info
    BLOCK_HASH=$(echo "$RESPONSE" | jq -r '.blockID')
    TIMESTAMP=$(echo "$RESPONSE" | jq -r '.block_header.raw_data.timestamp')
    TX_COUNT=$(echo "$RESPONSE" | jq -r '(.transactions // [] | length)')
    PRODUCER=$(echo "$RESPONSE" | jq -r '.block_header.raw_data.witness_address')
    
    # Convert timestamp to readable format
    DATETIME=$(date -d "@$((TIMESTAMP / 1000))" "+%Y-%m-%d %H:%M:%S")
    
    echo "📦 Block #$CURRENT_BLOCK | $TX_COUNT txs | $DATETIME | Producer: $PRODUCER"
    
    # Log transactions in block
    if [ "$TX_COUNT" -gt 0 ]; then
      echo "$RESPONSE" | jq -r '.transactions[]?.txID' | while read -r txid; do
        echo "  💸 Transaction: $txid"
      done
    fi
    
    LAST_BLOCK=$CURRENT_BLOCK
  fi
  
  sleep 3  # Check every 3 seconds (TRON block time)
done

# Network performance analysis script
#!/bin/bash
API_KEY="YOUR_API_KEY"
DURATION=${1:-60}  # Duration in seconds, default 60

echo "Collecting TRON network statistics for $DURATION seconds..."

START_TIME=$(date +%s)
END_TIME=$((START_TIME + DURATION))
TOTAL_BLOCKS=0
TOTAL_TXS=0
BLOCKS_FILE="/tmp/tron_blocks.json"

> "$BLOCKS_FILE"  # Clear file

while [ $(date +%s) -lt $END_TIME ]; do
  RESPONSE=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/getnowblock" \
    -H "Content-Type: application/json")
  
  BLOCK_NUMBER=$(echo "$RESPONSE" | jq -r '.block_header.raw_data.number')
  TX_COUNT=$(echo "$RESPONSE" | jq -r '(.transactions // [] | length)')
  
  if [ "$BLOCK_NUMBER" != "null" ]; then
    echo "$RESPONSE" >> "$BLOCKS_FILE"
    echo "Block #$BLOCK_NUMBER with $TX_COUNT transactions"
    ((TOTAL_BLOCKS++))
    TOTAL_TXS=$((TOTAL_TXS + TX_COUNT))
  fi
  
  sleep 3
done

# Calculate statistics
if [ $TOTAL_BLOCKS -gt 0 ]; then
  AVG_TXS_PER_BLOCK=$((TOTAL_TXS / TOTAL_BLOCKS))
  AVG_TPS=$((TOTAL_TXS / DURATION))
  
  echo ""
  echo "=== TRON Network Statistics ==="
  echo "Duration: $DURATION seconds"
  echo "Total blocks observed: $TOTAL_BLOCKS"
  echo "Total transactions: $TOTAL_TXS"
  echo "Average transactions per block: $AVG_TXS_PER_BLOCK"
  echo "Average TPS: $AVG_TPS"
  
  # Find most active producer
  echo ""
  echo "Block producers:"
  jq -r '.block_header.raw_data.witness_address' "$BLOCKS_FILE" | sort | uniq -c | sort -nr | head -5
else
  echo "No blocks collected during monitoring period"
fi

# Cleanup
rm -f "$BLOCKS_FILE"

# Real-time transaction finder
find_transaction_in_blocks() {
  local TX_ID=$1
  local MAX_CHECKS=${2:-20}
  local CHECK_COUNT=0
  
  echo "Searching for transaction $TX_ID in recent blocks..."
  
  while [ $CHECK_COUNT -lt $MAX_CHECKS ]; do
    RESPONSE=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/getnowblock" \
      -H "Content-Type: application/json")
    
    # Check if transaction is in this block
    FOUND=$(echo "$RESPONSE" | jq -r --arg txid "$TX_ID" '
      .transactions[]? | select(.txID == $txid) | .txID
    ')
    
    if [ "$FOUND" = "$TX_ID" ]; then
      BLOCK_NUMBER=$(echo "$RESPONSE" | jq -r '.block_header.raw_data.number')
      BLOCK_HASH=$(echo "$RESPONSE" | jq -r '.blockID')
      echo "✓ Transaction found in block #$BLOCK_NUMBER ($BLOCK_HASH)"
      return 0
    fi
    
    echo "Checking block... ($((CHECK_COUNT + 1))/$MAX_CHECKS)"
    ((CHECK_COUNT++))
    sleep 3
  done
  
  echo "✗ Transaction not found in the last $MAX_CHECKS blocks"
  return 1
}

# Usage examples:
# ./script.sh                           # Monitor blocks
# ./script.sh performance 120           # Collect stats for 2 minutes  
# ./script.sh find TX_ID_HERE           # Find transaction in recent blocks

case "${1:-monitor}" in
  "performance")
    # Run performance analysis
    ;;
  "find")
    find_transaction_in_blocks "$2"
    ;;
  *)
    # Default: monitor blocks
    ;;
esac
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get the latest block
async function getLatestBlock() {
  const response = await fetch(`${TRON_API}/wallet/getnowblock`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    }
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Enhanced block info with formatted data
async function getBlockInfo() {
  try {
    const block = await getLatestBlock();
    
    return {
      blockNumber: block.block_header.raw_data.number,
      blockHash: block.blockID,
      timestamp: block.block_header.raw_data.timestamp,
      datetime: new Date(block.block_header.raw_data.timestamp).toISOString(),
      transactionCount: block.transactions ? block.transactions.length : 0,
      producer: block.block_header.raw_data.witness_address,
      parentHash: block.block_header.raw_data.parentHash,
      version: block.block_header.raw_data.version,
      merkleRoot: block.block_header.raw_data.txTrieRoot,
      transactions: block.transactions || []
    };
  } catch (error) {
    console.error('Error fetching block info:', error);
    throw error;
  }
}

// Block monitoring with real-time updates
class TronBlockMonitor {
  constructor(apiKey, pollInterval = 3000) {
    this.apiKey = apiKey;
    this.pollInterval = pollInterval;
    this.lastBlockNumber = 0;
    this.isRunning = false;
    this.listeners = {
      newBlock: [],
      transaction: [],
      error: []
    };
  }
  
  on(event, callback) {
    if (this.listeners[event]) {
      this.listeners[event].push(callback);
    }
  }
  
  emit(event, data) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(callback => callback(data));
    }
  }
  
  async start() {
    this.isRunning = true;
    console.log('Starting TRON block monitor...');
    
    while (this.isRunning) {
      try {
        const blockInfo = await getBlockInfo();
        
        if (blockInfo.blockNumber > this.lastBlockNumber) {
          console.log(`New block #${blockInfo.blockNumber} with ${blockInfo.transactionCount} transactions`);
          
          this.emit('newBlock', blockInfo);
          
          // Emit transaction events
          if (blockInfo.transactions) {
            blockInfo.transactions.forEach(tx => {
              this.emit('transaction', {
                txId: tx.txID,
                blockNumber: blockInfo.blockNumber,
                transaction: tx
              });
            });
          }
          
          this.lastBlockNumber = blockInfo.blockNumber;
        }
        
      } catch (error) {
        console.error('Block monitoring error:', error);
        this.emit('error', error);
      }
      
      await new Promise(resolve => setTimeout(resolve, this.pollInterval));
    }
  }
  
  stop() {
    this.isRunning = false;
    console.log('Block monitor stopped');
  }
}

// Network performance analyzer
async function analyzeNetworkPerformance(sampleBlocks = 10) {
  const blocks = [];
  
  try {
    // Get current block
    let currentBlock = await getBlockInfo();
    blocks.push(currentBlock);
    
    // Get previous blocks (would need getBlockByNumber for historical data)
    // This is a simplified example
    console.log(`Analyzing network performance based on latest block...`);
    
    const analysis = {
      latestBlock: currentBlock.blockNumber,
      timestamp: currentBlock.datetime,
      transactionThroughput: currentBlock.transactionCount,
      estimatedTPS: currentBlock.transactionCount / 3, // 3-second blocks
      producer: currentBlock.producer,
      blockTime: 3000, // TRON's target block time
      networkHealth: currentBlock.transactionCount > 0 ? 'active' : 'low_activity'
    };
    
    return analysis;
  } catch (error) {
    console.error('Network analysis failed:', error);
    throw error;
  }
}

// Transaction finder - check if transaction is in latest blocks
async function findTransactionInRecentBlocks(txId, maxBlocks = 20) {
  const foundIn = {
    found: false,
    blockNumber: null,
    blockHash: null,
    position: null
  };
  
  try {
    // Check latest block
    const block = await getLatestBlock();
    
    if (block.transactions) {
      const txIndex = block.transactions.findIndex(tx => tx.txID === txId);
      if (txIndex !== -1) {
        foundIn.found = true;
        foundIn.blockNumber = block.block_header.raw_data.number;
        foundIn.blockHash = block.blockID;
        foundIn.position = txIndex;
      }
    }
    
    return foundIn;
  } catch (error) {
    console.error('Transaction search failed:', error);
    throw error;
  }
}

// Usage examples
(async () => {
  try {
    // Get latest block info
    const blockInfo = await getBlockInfo();
    console.log('Latest block:', blockInfo.blockNumber);
    console.log('Transactions:', blockInfo.transactionCount);
    console.log('Timestamp:', blockInfo.datetime);
    
    // Start block monitoring
    const monitor = new TronBlockMonitor('YOUR_API_KEY');
    
    monitor.on('newBlock', (block) => {
      console.log(`📦 New block: #${block.blockNumber} (${block.transactionCount} txs)`);
    });
    
    monitor.on('transaction', (tx) => {
      console.log(`💸 New transaction: ${tx.txId} in block ${tx.blockNumber}`);
    });
    
    // Start monitoring (comment out for non-continuous examples)
    // await monitor.start();
    
    // Analyze network performance
    const performance = await analyzeNetworkPerformance();
    console.log('Network performance:', performance);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import time
import threading
from datetime import datetime
from typing import Dict, List, Optional, Callable

class TronBlockClient:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def get_latest_block(self) -> Dict:
        """Get the latest block from TRON network"""
        url = f"{self.base_url}/wallet/getnowblock"
        
        response = requests.post(url, headers=self.headers)
        response.raise_for_status()
        
        return response.json()
    
    def get_block_info(self) -> Dict:
        """Get formatted block information"""
        try:
            block = self.get_latest_block()
            
            return {
                'block_number': block['block_header']['raw_data']['number'],
                'block_hash': block['blockID'],
                'timestamp': block['block_header']['raw_data']['timestamp'],
                'datetime': datetime.fromtimestamp(
                    block['block_header']['raw_data']['timestamp'] / 1000
                ).isoformat(),
                'transaction_count': len(block.get('transactions', [])),
                'producer': block['block_header']['raw_data']['witness_address'],
                'parent_hash': block['block_header']['raw_data']['parentHash'],
                'version': block['block_header']['raw_data']['version'],
                'merkle_root': block['block_header']['raw_data']['txTrieRoot'],
                'transactions': block.get('transactions', [])
            }
        except requests.RequestException as e:
            print(f"Error fetching block info: {e}")
            raise
    
    def analyze_network_performance(self, sample_blocks: int = 10) -> Dict:
        """Analyze network performance based on latest block"""
        try:
            block_info = self.get_block_info()
            
            analysis = {
                'latest_block': block_info['block_number'],
                'timestamp': block_info['datetime'],
                'transaction_throughput': block_info['transaction_count'],
                'estimated_tps': block_info['transaction_count'] / 3,  # 3-second blocks
                'producer': block_info['producer'],
                'block_time_ms': 3000,  # TRON's target block time
                'network_health': 'active' if block_info['transaction_count'] > 0 else 'low_activity'
            }
            
            return analysis
        except Exception as e:
            print(f"Network analysis failed: {e}")
            raise
    
    def find_transaction_in_latest_block(self, tx_id: str) -> Dict:
        """Check if transaction is in the latest block"""
        found_in = {
            'found': False,
            'block_number': None,
            'block_hash': None,
            'position': None
        }
        
        try:
            block = self.get_latest_block()
            
            if 'transactions' in block:
                for index, tx in enumerate(block['transactions']):
                    if tx['txID'] == tx_id:
                        found_in['found'] = True
                        found_in['block_number'] = block['block_header']['raw_data']['number']
                        found_in['block_hash'] = block['blockID']
                        found_in['position'] = index
                        break
            
            return found_in
        except Exception as e:
            print(f"Transaction search failed: {e}")
            raise

class TronBlockMonitor:
    def __init__(self, api_key: str, poll_interval: int = 3):
        self.client = TronBlockClient(api_key)
        self.poll_interval = poll_interval
        self.last_block_number = 0
        self.is_running = False
        self.listeners = {
            'new_block': [],
            'transaction': [],
            'error': []
        }
        self.monitor_thread = None
    
    def on(self, event: str, callback: Callable):
        """Register event listener"""
        if event in self.listeners:
            self.listeners[event].append(callback)
    
    def emit(self, event: str, data):
        """Emit event to listeners"""
        if event in self.listeners:
            for callback in self.listeners[event]:
                callback(data)
    
    def start(self):
        """Start block monitoring in background thread"""
        if self.is_running:
            return
        
        self.is_running = True
        self.monitor_thread = threading.Thread(target=self._monitor_loop)
        self.monitor_thread.daemon = True
        self.monitor_thread.start()
        print("TRON block monitor started")
    
    def stop(self):
        """Stop block monitoring"""
        self.is_running = False
        if self.monitor_thread:
            self.monitor_thread.join()
        print("TRON block monitor stopped")
    
    def _monitor_loop(self):
        """Main monitoring loop"""
        while self.is_running:
            try:
                block_info = self.client.get_block_info()
                
                if block_info['block_number'] > self.last_block_number:
                    print(f"New block #{block_info['block_number']} "
                          f"with {block_info['transaction_count']} transactions")
                    
                    self.emit('new_block', block_info)
                    
                    # Emit transaction events
                    for tx in block_info['transactions']:
                        self.emit('transaction', {
                            'tx_id': tx['txID'],
                            'block_number': block_info['block_number'],
                            'transaction': tx
                        })
                    
                    self.last_block_number = block_info['block_number']
                
            except Exception as e:
                print(f"Block monitoring error: {e}")
                self.emit('error', e)
            
            time.sleep(self.poll_interval)

class TronNetworkStats:
    def __init__(self, api_key: str):
        self.client = TronBlockClient(api_key)
        self.stats_history = []
    
    def collect_stats(self, duration_minutes: int = 10):
        """Collect network statistics over time"""
        start_time = time.time()
        end_time = start_time + (duration_minutes * 60)
        
        print(f"Collecting TRON network stats for {duration_minutes} minutes...")
        
        while time.time() < end_time:
            try:
                block_info = self.client.get_block_info()
                
                stats = {
                    'timestamp': time.time(),
                    'block_number': block_info['block_number'],
                    'transaction_count': block_info['transaction_count'],
                    'producer': block_info['producer']
                }
                
                self.stats_history.append(stats)
                print(f"Block #{block_info['block_number']}: "
                      f"{block_info['transaction_count']} transactions")
                
                time.sleep(3)  # Check every 3 seconds (block time)
                
            except Exception as e:
                print(f"Stats collection error: {e}")
                time.sleep(1)
        
        return self.analyze_collected_stats()
    
    def analyze_collected_stats(self) -> Dict:
        """Analyze collected statistics"""
        if not self.stats_history:
            return {'error': 'No statistics collected'}
        
        total_transactions = sum(stat['transaction_count'] for stat in self.stats_history)
        total_blocks = len(self.stats_history)
        duration_seconds = (self.stats_history[-1]['timestamp'] - 
                          self.stats_history[0]['timestamp'])
        
        producers = {}
        for stat in self.stats_history:
            producer = stat['producer']
            producers[producer] = producers.get(producer, 0) + 1
        
        analysis = {
            'total_blocks_observed': total_blocks,
            'total_transactions': total_transactions,
            'average_tx_per_block': total_transactions / total_blocks if total_blocks > 0 else 0,
            'average_tps': total_transactions / duration_seconds if duration_seconds > 0 else 0,
            'duration_seconds': duration_seconds,
            'block_producers': producers,
            'most_active_producer': max(producers.items(), key=lambda x: x[1])[0] if producers else None
        }
        
        return analysis

# Usage examples
if __name__ == "__main__":
    client = TronBlockClient('YOUR_API_KEY')
    
    try:
        # Get latest block info
        block_info = client.get_block_info()
        print(f"Latest block: #{block_info['block_number']}")
        print(f"Transactions: {block_info['transaction_count']}")
        print(f"Timestamp: {block_info['datetime']}")
        
        # Analyze network performance
        performance = client.analyze_network_performance()
        print(f"Network performance: {performance}")
        
        # Set up block monitoring
        monitor = TronBlockMonitor('YOUR_API_KEY')
        
        def on_new_block(block):
            print(f"📦 New block: #{block['block_number']} "
                  f"({block['transaction_count']} txs)")
        
        def on_transaction(tx):
            print(f"💸 New transaction: {tx['tx_id']} "
                  f"in block {tx['block_number']}")
        
        monitor.on('new_block', on_new_block)
        monitor.on('transaction', on_transaction)
        
        # Start monitoring (uncomment for continuous monitoring)
        # monitor.start()
        # time.sleep(30)  # Monitor for 30 seconds
        # monitor.stop()
        
        # Collect network statistics
        stats_collector = TronNetworkStats('YOUR_API_KEY')
        # stats = stats_collector.collect_stats(1)  # Collect for 1 minute
        # print(f"Network statistics: {stats}")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Latest Block Response

```json
{
  "blockID": "00000000032a9c4bd8b6b8e1a8e8d6c4b2a09f8e7d6c5b4a39291807f6e5d4c3b2",
  "block_header": {
    "raw_data": {
      "number": 52895819,
      "txTrieRoot": "0000000000000000000000000000000000000000000000000000000000000000",
      "witness_address": "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH",
      "parentHash": "00000000032a9c4a9d8b6b8e1a8e8d6c4b2a09f8e7d6c5b4a39291807f6e5d4c3",
      "version": 27,
      "timestamp": 1734567890000
    },
    "witness_signature": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
  },
  "transactions": [
    {
      "ret": [{"contractRet": "SUCCESS"}],
      "signature": ["7a8b9c0d1e2f3456789012345678901234567890123456789012345678901234567890"],
      "txID": "94eea63bb6774c8fc4f4c9d1b62c1e8c2f7c8c2e4d3a2b1c0d9e8f7a6b5c4d3e2f1",
      "raw_data": {
        "contract": [
          {
            "parameter": {
              "value": {
                "amount": 1000000,
                "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
                "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
              },
              "type_url": "type.googleapis.com/protocol.TransferContract"
            },
            "type": "TransferContract"
          }
        ],
        "ref_block_bytes": "9c4a",
        "ref_block_hash": "b8e1a8e8d6c4b2a0",
        "expiration": 1734567950000,
        "timestamp": 1734567890000
      }
    }
  ]
}
```

### Empty Block Response

```json
{
  "blockID": "00000000032a9c4bd8b6b8e1a8e8d6c4b2a09f8e7d6c5b4a39291807f6e5d4c3b2",
  "block_header": {
    "raw_data": {
      "number": 52895820,
      "txTrieRoot": "0000000000000000000000000000000000000000000000000000000000000000",
      "witness_address": "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH",
      "parentHash": "00000000032a9c4a9d8b6b8e1a8e8d6c4b2a09f8e7d6c5b4a39291807f6e5d4c3",
      "version": 27,
      "timestamp": 1734567893000
    },
    "witness_signature": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
  }
}
```

## Common Use Cases

### 1. Real-Time Block Explorer

```javascript
class TronBlockExplorer {
  constructor(apiKey) {
    this.client = new TronBlockClient(apiKey);
    this.blockCache = new Map();
    this.subscribers = new Set();
  }
  
  async getLatestBlockData() {
    try {
      const blockInfo = await this.client.getBlockInfo();
      
      // Cache block data
      this.blockCache.set(blockInfo.blockNumber, blockInfo);
      
      // Keep only last 100 blocks in cache
      if (this.blockCache.size > 100) {
        const oldestBlock = Math.min(...this.blockCache.keys());
        this.blockCache.delete(oldestBlock);
      }
      
      return {
        ...blockInfo,
        cached: false,
        timeAgo: this.calculateTimeAgo(blockInfo.timestamp)
      };
    } catch (error) {
      console.error('Failed to fetch block data:', error);
      throw error;
    }
  }
  
  calculateTimeAgo(timestamp) {
    const now = Date.now();
    const diff = now - timestamp;
    
    if (diff < 10000) return 'just now';
    if (diff < 60000) return `${Math.floor(diff / 1000)}s ago`;
    if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
    return `${Math.floor(diff / 3600000)}h ago`;
  }
  
  subscribeToBlocks(callback) {
    this.subscribers.add(callback);
    return () => this.subscribers.delete(callback);
  }
  
  async startRealTimeUpdates() {
    setInterval(async () => {
      try {
        const blockData = await this.getLatestBlockData();
        this.subscribers.forEach(callback => callback(blockData));
      } catch (error) {
        console.error('Real-time update failed:', error);
      }
    }, 3000);
  }
}
```

### 2. Transaction Confirmation Tracker

```javascript
class TransactionConfirmationTracker {
  constructor(apiKey) {
    this.client = new TronBlockClient(apiKey);
    this.pendingTransactions = new Map();
    this.confirmedTransactions = new Map();
  }
  
  async trackTransaction(txId, requiredConfirmations = 1) {
    this.pendingTransactions.set(txId, {
      txId,
      requiredConfirmations,
      currentConfirmations: 0,
      firstSeenBlock: null,
      startTime: Date.now()
    });
    
    return new Promise((resolve, reject) => {
      const checkConfirmation = async () => {
        try {
          const found = await this.client.findTransactionInLatestBlock(txId);
          
          if (found.found) {
            const tracking = this.pendingTransactions.get(txId);
            if (!tracking.firstSeenBlock) {
              tracking.firstSeenBlock = found.blockNumber;
            }
            
            // Calculate confirmations based on current block
            const latestBlock = await this.client.getBlockInfo();
            const confirmations = latestBlock.blockNumber - tracking.firstSeenBlock + 1;
            tracking.currentConfirmations = confirmations;
            
            if (confirmations >= requiredConfirmations) {
              this.pendingTransactions.delete(txId);
              this.confirmedTransactions.set(txId, {
                ...tracking,
                confirmedAt: Date.now(),
                finalBlockNumber: latestBlock.blockNumber
              });
              
              resolve({
                confirmed: true,
                confirmations,
                blockNumber: tracking.firstSeenBlock,
                confirmationTime: Date.now() - tracking.startTime
              });
            }
          }
          
          // Continue checking
          setTimeout(checkConfirmation, 3000);
        } catch (error) {
          reject(error);
        }
      };
      
      checkConfirmation();
    });
  }
  
  getTransactionStatus(txId) {
    if (this.confirmedTransactions.has(txId)) {
      return { status: 'confirmed', ...this.confirmedTransactions.get(txId) };
    }
    
    if (this.pendingTransactions.has(txId)) {
      return { status: 'pending', ...this.pendingTransactions.get(txId) };
    }
    
    return { status: 'unknown' };
  }
}
```

### 3. Network Health Monitor

```javascript
class TronNetworkHealthMonitor {
  constructor(apiKey) {
    this.client = new TronBlockClient(apiKey);
    this.healthMetrics = {
      blockTimes: [],
      transactionCounts: [],
      producers: new Map(),
      lastUpdate: null
    };
  }
  
  async startMonitoring(durationMinutes = 60) {
    const endTime = Date.now() + (durationMinutes * 60 * 1000);
    let lastBlockNumber = 0;
    let lastBlockTime = null;
    
    console.log(`Starting network health monitoring for ${durationMinutes} minutes...`);
    
    while (Date.now() < endTime) {
      try {
        const blockInfo = await this.client.getBlockInfo();
        
        if (blockInfo.blockNumber > lastBlockNumber) {
          // Calculate block time
          if (lastBlockTime) {
            const blockTime = blockInfo.timestamp - lastBlockTime;
            this.healthMetrics.blockTimes.push(blockTime);
          }
          
          // Track transaction count
          this.healthMetrics.transactionCounts.push(blockInfo.transactionCount);
          
          // Track producer
          const producer = blockInfo.producer;
          this.healthMetrics.producers.set(
            producer, 
            (this.healthMetrics.producers.get(producer) || 0) + 1
          );
          
          lastBlockNumber = blockInfo.blockNumber;
          lastBlockTime = blockInfo.timestamp;
          
          console.log(`Block #${blockInfo.blockNumber}: ${blockInfo.transactionCount} txs, Producer: ${producer}`);
        }
        
        await new Promise(resolve => setTimeout(resolve, 3000));
        
      } catch (error) {
        console.error('Health monitoring error:', error);
        await new Promise(resolve => setTimeout(resolve, 5000));
      }
    }
    
    return this.generateHealthReport();
  }
  
  generateHealthReport() {
    const { blockTimes, transactionCounts, producers } = this.healthMetrics;
    
    const avgBlockTime = blockTimes.length > 0 
      ? blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length 
      : 0;
    
    const avgTxPerBlock = transactionCounts.length > 0
      ? transactionCounts.reduce((a, b) => a + b, 0) / transactionCounts.length
      : 0;
    
    const totalTx = transactionCounts.reduce((a, b) => a + b, 0);
    const avgTPS = totalTx / (blockTimes.length * (avgBlockTime / 1000));
    
    // Analyze producer distribution
    const totalBlocks = producers.size > 0 
      ? Array.from(producers.values()).reduce((a, b) => a + b, 0)
      : 0;
    
    const producerStats = Array.from(producers.entries())
      .map(([address, count]) => ({
        address,
        blocks: count,
        percentage: (count / totalBlocks * 100).toFixed(2)
      }))
      .sort((a, b) => b.blocks - a.blocks);
    
    return {
      monitoringPeriod: {
        blocksObserved: blockTimes.length,
        totalTransactions: totalTx,
        uniqueProducers: producers.size
      },
      performance: {
        averageBlockTime: avgBlockTime.toFixed(2) + 'ms',
        targetBlockTime: '3000ms',
        blockTimeVariance: this.calculateVariance(blockTimes).toFixed(2),
        averageTransactionsPerBlock: avgTxPerBlock.toFixed(2),
        averageTPS: avgTPS.toFixed(2)
      },
      networkHealth: {
        status: avgBlockTime < 4000 && avgBlockTime > 2000 ? 'healthy' : 'concerning',
        blockTimeHealth: avgBlockTime < 4000 ? 'good' : 'slow',
        transactionActivity: avgTxPerBlock > 1 ? 'active' : 'low'
      },
      producers: producerStats.slice(0, 10), // Top 10 producers
      recommendations: this.generateRecommendations(avgBlockTime, avgTxPerBlock, producers.size)
    };
  }
  
  calculateVariance(values) {
    if (values.length === 0) return 0;
    const mean = values.reduce((a, b) => a + b, 0) / values.length;
    const variance = values.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / values.length;
    return Math.sqrt(variance);
  }
  
  generateRecommendations(avgBlockTime, avgTxPerBlock, producerCount) {
    const recommendations = [];
    
    if (avgBlockTime > 4000) {
      recommendations.push('Block times are slower than expected - monitor network congestion');
    }
    
    if (avgTxPerBlock < 1) {
      recommendations.push('Low transaction activity - network may be underutilized');
    }
    
    if (producerCount < 20) {
      recommendations.push('Limited producer diversity observed - consider longer monitoring period');
    }
    
    if (recommendations.length === 0) {
      recommendations.push('Network appears to be operating normally');
    }
    
    return recommendations;
  }
}
```

### 4. DApp Synchronization Service

```javascript
class TronDAppSync {
  constructor(apiKey, contractAddresses = []) {
    this.client = new TronBlockClient(apiKey);
    this.contractAddresses = contractAddresses;
    this.lastSyncedBlock = 0;
    this.eventHandlers = new Map();
  }
  
  onContractEvent(contractAddress, eventType, handler) {
    const key = `${contractAddress}:${eventType}`;
    if (!this.eventHandlers.has(key)) {
      this.eventHandlers.set(key, []);
    }
    this.eventHandlers.get(key).push(handler);
  }
  
  async syncToLatest() {
    try {
      const latestBlock = await this.client.getBlockInfo();
      
      if (latestBlock.blockNumber > this.lastSyncedBlock) {
        console.log(`Syncing to block #${latestBlock.blockNumber}...`);
        
        // Process transactions in the latest block
        await this.processBlockTransactions(latestBlock);
        
        this.lastSyncedBlock = latestBlock.blockNumber;
        
        return {
          syncedToBlock: latestBlock.blockNumber,
          transactionsProcessed: latestBlock.transactionCount,
          timestamp: latestBlock.datetime
        };
      }
      
      return {
        syncedToBlock: this.lastSyncedBlock,
        message: 'Already up to date'
      };
    } catch (error) {
      console.error('Sync failed:', error);
      throw error;
    }
  }
  
  async processBlockTransactions(blockInfo) {
    for (const tx of blockInfo.transactions) {
      if (this.isContractTransaction(tx)) {
        await this.processContractTransaction(tx, blockInfo.blockNumber);
      }
    }
  }
  
  isContractTransaction(tx) {
    if (!tx.raw_data?.contract?.[0]) return false;
    
    const contract = tx.raw_data.contract[0];
    const contractAddress = contract.parameter?.value?.contract_address;
    
    return this.contractAddresses.includes(contractAddress);
  }
  
  async processContractTransaction(tx, blockNumber) {
    const contract = tx.raw_data.contract[0];
    const contractAddress = contract.parameter?.value?.contract_address;
    const contractType = contract.type;
    
    // Emit events for contract interactions
    const eventKey = `${contractAddress}:${contractType}`;
    const handlers = this.eventHandlers.get(eventKey) || [];
    
    for (const handler of handlers) {
      try {
        await handler({
          txId: tx.txID,
          contractAddress,
          contractType,
          blockNumber,
          transaction: tx
        });
      } catch (error) {
        console.error(`Event handler error for ${eventKey}:`, error);
      }
    }
  }
  
  async startAutoSync(intervalSeconds = 3) {
    console.log(`Starting auto-sync every ${intervalSeconds} seconds...`);
    
    const syncInterval = setInterval(async () => {
      try {
        const result = await this.syncToLatest();
        if (result.transactionsProcessed > 0) {
          console.log(`Synced: Block #${result.syncedToBlock} (${result.transactionsProcessed} txs)`);
        }
      } catch (error) {
        console.error('Auto-sync error:', error);
      }
    }, intervalSeconds * 1000);
    
    return () => clearInterval(syncInterval);
  }
}
```

## Performance Tips

1. **Efficient Polling** - Use 3-second intervals to match TRON's block time
2. **Cache Management** - Cache recent block data to avoid redundant requests
3. **Event-Driven Updates** - Use real-time monitoring instead of constant polling
4. **Batch Processing** - Process multiple transactions efficiently

```javascript
// Optimized block monitoring with caching
class OptimizedBlockMonitor {
  constructor(apiKey, options = {}) {
    this.client = new TronBlockClient(apiKey);
    this.cache = new Map();
    this.options = {
      cacheSize: 100,
      pollInterval: 3000,
      ...options
    };
  }
  
  async getBlockWithCache(blockNumber = 'latest') {
    if (blockNumber === 'latest') {
      // Always fetch latest block
      const block = await this.client.getBlockInfo();
      this.addToCache(block.blockNumber, block);
      return block;
    }
    
    // Check cache first
    if (this.cache.has(blockNumber)) {
      return this.cache.get(blockNumber);
    }
    
    // Fetch and cache
    const block = await this.client.getBlockInfo();
    this.addToCache(block.blockNumber, block);
    return block;
  }
  
  addToCache(blockNumber, block) {
    this.cache.set(blockNumber, block);
    
    // Maintain cache size
    if (this.cache.size > this.options.cacheSize) {
      const oldestKey = Math.min(...this.cache.keys());
      this.cache.delete(oldestKey);
    }
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/gettransactionbyid - Get TRON Transactio...

# wallet/gettransactionbyid - Get TRON Transactio...

**Dwellir's TRON endpoints** retrieve transaction details in under 50ms with comprehensive status information.
Track payments, confirmations, and smart contract executions in real-time.

[Track your transactions](https://dashboard.dwellir.com/register)

Retrieves detailed information about a specific transaction using its transaction ID (hash). Essential for tracking transaction status, confirmations, and execution results.

## When to Use This Method

`wallet/gettransactionbyid` is essential for:

- **Transaction Confirmation** - Check if transaction was successful and confirmed
- **Payment Tracking** - Monitor payment status in real-time
- **Error Debugging** - Analyze failed transactions and error messages
- **Fee Analysis** - Review bandwidth and energy consumption
- **Smart Contract Results** - Get contract execution results and logs

## Request Parameters

- `value` (`string, required`): Transaction ID (hash) to lookup Example: `"2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5"`
- `visible` (`boolean, optional`): `true` - Use Base58 address format in response `false` - Use hex address format in response

## Request Example

```json
{
  "value": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5",
  "visible": true
}
```

## Response Fields

- `result` (`OBJECT, required`): `ret` - Execution result array with status and fees `signature` - Array of transaction signatures `txID` - Transaction identifier `raw_data` - Original transaction data `raw_data_hex` - Hex encoded transaction data `SUCCESS` - Transaction executed successfully `REVERT` - Smart contract execution reverted `UNKNOWN` - Transaction not found or pending

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get transaction by ID
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/gettransactionbyid" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5",
    "visible": true
  }'

# Parse transaction details
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/gettransactionbyid" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5",
    "visible": true
  }' | jq '{
    tx_id: .txID,
    status: .ret[0].contractRet // "NOT_FOUND",
    successful: (.ret[0].contractRet == "SUCCESS"),
    block_number: .blockNumber,
    timestamp: .blockTimeStamp,
    fee: .ret[0].fee // 0,
    energy_used: .ret[0].energy_usage // 0,
    contract_type: .raw_data.contract[0].type,
    contract_details: .raw_data.contract[0].parameter.value
  }'

# Transaction monitoring script
#!/bin/bash
API_KEY="YOUR_API_KEY"

# Function to get transaction details
get_transaction() {
  local tx_id=$1
  
  curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/gettransactionbyid" \
    -H "Content-Type: application/json" \
    -d "{\"value\": \"$tx_id\", \"visible\": true}"
}

# Function to analyze transaction
analyze_transaction() {
  local tx_id=$1
  local tx_data=$(get_transaction "$tx_id")
  
  # Check if transaction exists
  local tx_id_response=$(echo "$tx_data" | jq -r '.txID // empty')
  
  if [ -z "$tx_id_response" ]; then
    echo "❌ Transaction not found: $tx_id"
    return 1
  fi
  
  # Extract key information
  local status=$(echo "$tx_data" | jq -r '.ret[0].contractRet // "UNKNOWN"')
  local block_number=$(echo "$tx_data" | jq -r '.blockNumber // empty')
  local timestamp=$(echo "$tx_data" | jq -r '.blockTimeStamp // empty')
  local fee=$(echo "$tx_data" | jq -r '.ret[0].fee // 0')
  local energy_used=$(echo "$tx_data" | jq -r '.ret[0].energy_usage // 0')
  local contract_type=$(echo "$tx_data" | jq -r '.raw_data.contract[0].type // "UNKNOWN"')
  
  echo "=== Transaction Analysis: $tx_id ==="
  echo "Status: $status"
  echo "Contract Type: $contract_type"
  
  if [ -n "$block_number" ]; then
    echo "✅ Confirmed in block: $block_number"
    if [ -n "$timestamp" ]; then
      local readable_time=$(date -d "@$((timestamp / 1000))" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "Invalid timestamp")
      echo "Time: $readable_time"
    fi
  else
    echo "⏳ Pending confirmation"
  fi
  
  echo "Fee: $fee SUN"
  echo "Energy Used: $energy_used"
  
  # Parse contract details based on type
  case "$contract_type" in
    "TransferContract")
      local from=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.owner_address')
      local to=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.to_address')
      local amount=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.amount')
      local amount_trx=$(echo "scale=6; $amount / 1000000" | bc -l)
      
      echo ""
      echo "TRX Transfer Details:"
      echo "  From: $from"
      echo "  To: $to"
      echo "  Amount: $amount_trx TRX ($amount SUN)"
      ;;
      
    "TriggerSmartContract")
      local caller=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.owner_address')
      local contract=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.contract_address')
      local call_value=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.call_value // 0')
      
      echo ""
      echo "Smart Contract Call Details:"
      echo "  Caller: $caller"
      echo "  Contract: $contract"
      echo "  Call Value: $call_value SUN"
      ;;
  esac
  
  echo ""
}

# Function to track transaction until confirmed
track_transaction() {
  local tx_id=$1
  local timeout=${2:-300}  # Default 5 minutes
  local check_interval=${3:-5}  # Default 5 seconds
  
  echo "Tracking transaction: $tx_id"
  echo "Timeout: ${timeout}s, Check interval: ${check_interval}s"
  echo ""
  
  local start_time=$(date +%s)
  local end_time=$((start_time + timeout))
  
  while [ $(date +%s) -lt $end_time ]; do
    local tx_data=$(get_transaction "$tx_id")
    local tx_id_response=$(echo "$tx_data" | jq -r '.txID // empty')
    
    if [ -n "$tx_id_response" ]; then
      local block_number=$(echo "$tx_data" | jq -r '.blockNumber // empty')
      local status=$(echo "$tx_data" | jq -r '.ret[0].contractRet // "UNKNOWN"')
      
      if [ -n "$block_number" ]; then
        local elapsed=$(($(date +%s) - start_time))
        echo "✅ Transaction confirmed after ${elapsed}s"
        analyze_transaction "$tx_id"
        return 0
      else
        echo "⏳ Transaction found in mempool, waiting for confirmation..."
      fi
    else
      echo "🔍 Transaction not found yet, checking again..."
    fi
    
    sleep $check_interval
  done
  
  echo "⏰ Tracking timeout after ${timeout}s"
  return 1
}

# Function to verify payment
verify_payment() {
  local tx_id=$1
  local expected_amount=$2
  local expected_recipient=$3
  
  echo "Verifying payment: $tx_id"
  echo "Expected: $expected_amount SUN to $expected_recipient"
  echo ""
  
  local tx_data=$(get_transaction "$tx_id")
  local tx_id_response=$(echo "$tx_data" | jq -r '.txID // empty')
  
  if [ -z "$tx_id_response" ]; then
    echo "❌ Verification failed: Transaction not found"
    return 1
  fi
  
  local status=$(echo "$tx_data" | jq -r '.ret[0].contractRet // "UNKNOWN"')
  
  if [ "$status" != "SUCCESS" ]; then
    echo "❌ Verification failed: Transaction status is $status"
    return 1
  fi
  
  local contract_type=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value | keys[0]')
  
  # Check if it's a TRX transfer
  local actual_amount=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.amount // empty')
  local actual_recipient=$(echo "$tx_data" | jq -r '.raw_data.contract[0].parameter.value.to_address // empty')
  
  if [ -z "$actual_amount" ] || [ -z "$actual_recipient" ]; then
    echo "❌ Verification failed: Not a TRX transfer transaction"
    return 1
  fi
  
  if [ "$actual_amount" = "$expected_amount" ] && [ "$actual_recipient" = "$expected_recipient" ]; then
    echo "✅ Payment verified successfully"
    echo "  Amount: $actual_amount SUN"
    echo "  Recipient: $actual_recipient"
    return 0
  else
    echo "❌ Payment verification failed"
    echo "  Expected amount: $expected_amount SUN"
    echo "  Actual amount: $actual_amount SUN"
    echo "  Expected recipient: $expected_recipient"
    echo "  Actual recipient: $actual_recipient"
    return 1
  fi
}

# Batch transaction analysis
batch_analyze() {
  local tx_file=$1
  
  if [ ! -f "$tx_file" ]; then
    echo "Error: Transaction list file not found: $tx_file"
    echo "Create a file with one transaction ID per line"
    return 1
  fi
  
  echo "=== Batch Transaction Analysis ==="
  echo "Processing transactions from: $tx_file"
  echo ""
  
  local total=0
  local successful=0
  local failed=0
  local pending=0
  local not_found=0
  
  while IFS= read -r tx_id; do
    # Skip empty lines
    [ -z "$tx_id" ] && continue
    
    ((total++))
    
    local tx_data=$(get_transaction "$tx_id")
    local tx_id_response=$(echo "$tx_data" | jq -r '.txID // empty')
    
    if [ -z "$tx_id_response" ]; then
      echo "❌ $tx_id - NOT FOUND"
      ((not_found++))
    else
      local status=$(echo "$tx_data" | jq -r '.ret[0].contractRet // "UNKNOWN"')
      local block_number=$(echo "$tx_data" | jq -r '.blockNumber // empty')
      
      if [ -z "$block_number" ]; then
        echo "⏳ $tx_id - PENDING"
        ((pending++))
      elif [ "$status" = "SUCCESS" ]; then
        echo "✅ $tx_id - SUCCESS (Block: $block_number)"
        ((successful++))
      else
        echo "❌ $tx_id - FAILED ($status)"
        ((failed++))
      fi
    fi
  done < "$tx_file"
  
  echo ""
  echo "=== Summary ==="
  echo "Total: $total"
  echo "Successful: $successful"
  echo "Failed: $failed"
  echo "Pending: $pending"
  echo "Not Found: $not_found"
}

# Usage examples
case "${1:-analyze}" in
  "analyze")
    analyze_transaction "$2"
    ;;
  "track")
    track_transaction "$2" "$3" "$4"
    ;;
  "verify")
    verify_payment "$2" "$3" "$4"
    ;;
  "batch")
    batch_analyze "$2"
    ;;
  *)
    echo "Usage: $0 {analyze|track|verify|batch} [args...]"
    echo ""
    echo "Commands:"
    echo "  analyze TX_ID                           - Analyze single transaction"
    echo "  track TX_ID [TIMEOUT] [INTERVAL]       - Track until confirmed"
    echo "  verify TX_ID AMOUNT RECIPIENT          - Verify payment"
    echo "  batch TX_LIST_FILE                     - Analyze multiple transactions"
    echo ""
    echo "Examples:"
    echo "  $0 analyze 2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5"
    echo "  $0 track 2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5 300 5"
    echo "  $0 verify 2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5 1000000 TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
    echo "  $0 batch transactions.txt"
    ;;
esac
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Get transaction by ID
async function getTransactionById(txId) {
  const response = await fetch(`${TRON_API}/wallet/gettransactionbyid`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      value: txId,
      visible: true
    })
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}

// Enhanced transaction analyzer
class TronTransactionAnalyzer {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }
  
  async getTransactionDetails(txId) {
    try {
      const transaction = await this.getTransactionById(txId);
      
      if (!transaction.txID) {
        return {
          found: false,
          txId: txId,
          status: 'not_found',
          message: 'Transaction not found'
        };
      }
      
      const result = transaction.ret?.[0] || {};
      const contract = transaction.raw_data?.contract?.[0] || {};
      
      return {
        found: true,
        txId: transaction.txID,
        status: result.contractRet || 'UNKNOWN',
        successful: result.contractRet === 'SUCCESS',
        blockNumber: transaction.blockNumber,
        blockTimeStamp: transaction.blockTimeStamp,
        fee: result.fee || 0,
        energyUsed: result.energy_usage || 0,
        netUsed: result.net_usage || 0,
        contractType: contract.type,
        contractDetails: this.parseContract(contract),
        confirmations: transaction.confirmations || 0,
        rawTransaction: transaction
      };
    } catch (error) {
      console.error('Error getting transaction details:', error);
      throw error;
    }
  }
  
  async getTransactionById(txId) {
    const response = await fetch(`${this.apiUrl}/wallet/gettransactionbyid`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ value: txId, visible: true })
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    return await response.json();
  }
  
  parseContract(contract) {
    if (!contract.parameter?.value) return null;
    
    const value = contract.parameter.value;
    
    switch (contract.type) {
      case 'TransferContract':
        return {
          type: 'TRX Transfer',
          from: value.owner_address,
          to: value.to_address,
          amount: value.amount,
          amountTRX: (value.amount / 1000000).toFixed(6)
        };
        
      case 'TriggerSmartContract':
        return {
          type: 'Smart Contract Call',
          caller: value.owner_address,
          contract: value.contract_address,
          data: value.data,
          callValue: value.call_value || 0
        };
        
      case 'TransferAssetContract':
        return {
          type: 'TRC10 Token Transfer',
          from: value.owner_address,
          to: value.to_address,
          asset: value.asset_name,
          amount: value.amount
        };
        
      case 'FreezeBalanceContract':
        return {
          type: 'Freeze TRX',
          owner: value.owner_address,
          amount: value.frozen_balance,
          duration: value.frozen_duration,
          resource: value.resource
        };
        
      case 'UnfreezeBalanceContract':
        return {
          type: 'Unfreeze TRX',
          owner: value.owner_address,
          resource: value.resource
        };
        
      default:
        return {
          type: contract.type,
          details: value
        };
    }
  }
  
  async trackTransactionStatus(txId, timeoutMs = 60000) {
    const startTime = Date.now();
    const checkInterval = 3000; // Check every 3 seconds
    
    while (Date.now() - startTime < timeoutMs) {
      try {
        const details = await this.getTransactionDetails(txId);
        
        if (details.found) {
          if (details.blockNumber) {
            return {
              ...details,
              trackingStatus: 'confirmed',
              trackingTime: Date.now() - startTime
            };
          } else {
            // Found but not yet in block
            console.log('Transaction found in mempool, waiting for confirmation...');
          }
        } else {
          console.log('Transaction not found, checking again...');
        }
        
        await new Promise(resolve => setTimeout(resolve, checkInterval));
        
      } catch (error) {
        console.log('Error tracking transaction:', error.message);
      }
    }
    
    return {
      found: false,
      txId: txId,
      trackingStatus: 'timeout',
      trackingTime: timeoutMs,
      message: 'Transaction tracking timeout'
    };
  }
}

// Transaction monitor for multiple transactions
class TronTransactionMonitor {
  constructor(apiKey) {
    this.analyzer = new TronTransactionAnalyzer(apiKey);
    this.monitoredTxs = new Map();
    this.callbacks = new Map();
  }
  
  async monitor(txId, callback = null, timeoutMs = 300000) {
    if (this.monitoredTxs.has(txId)) {
      console.log(`Already monitoring transaction ${txId}`);
      return;
    }
    
    this.monitoredTxs.set(txId, {
      startTime: Date.now(),
      timeout: timeoutMs,
      status: 'monitoring'
    });
    
    if (callback) {
      this.callbacks.set(txId, callback);
    }
    
    // Start monitoring in background
    this.startMonitoring(txId);
  }
  
  async startMonitoring(txId) {
    const monitorInfo = this.monitoredTxs.get(txId);
    const callback = this.callbacks.get(txId);
    
    while (this.monitoredTxs.has(txId)) {
      try {
        const details = await this.analyzer.getTransactionDetails(txId);
        
        if (details.found && details.blockNumber) {
          // Transaction confirmed
          monitorInfo.status = 'confirmed';
          monitorInfo.details = details;
          
          if (callback) callback(details);
          
          console.log(`✅ Transaction ${txId} confirmed in block ${details.blockNumber}`);
          this.stopMonitoring(txId);
          break;
        }
        
        // Check timeout
        if (Date.now() - monitorInfo.startTime > monitorInfo.timeout) {
          monitorInfo.status = 'timeout';
          
          if (callback) {
            callback({
              found: false,
              txId: txId,
              status: 'timeout',
              message: 'Monitoring timeout'
            });
          }
          
          console.log(`⏰ Transaction ${txId} monitoring timeout`);
          this.stopMonitoring(txId);
          break;
        }
        
        await new Promise(resolve => setTimeout(resolve, 3000));
        
      } catch (error) {
        console.error(`Error monitoring transaction ${txId}:`, error);
        await new Promise(resolve => setTimeout(resolve, 5000));
      }
    }
  }
  
  stopMonitoring(txId) {
    this.monitoredTxs.delete(txId);
    this.callbacks.delete(txId);
  }
  
  getMonitoredTransactions() {
    return Array.from(this.monitoredTxs.entries()).map(([txId, info]) => ({
      txId,
      ...info
    }));
  }
}

// Payment verification system
class TronPaymentVerifier {
  constructor(apiKey) {
    this.analyzer = new TronTransactionAnalyzer(apiKey);
  }
  
  async verifyPayment(txId, expectedAmount, expectedRecipient, tokenContract = null) {
    try {
      const details = await this.analyzer.getTransactionDetails(txId);
      
      if (!details.found) {
        return {
          verified: false,
          reason: 'Transaction not found',
          details: null
        };
      }
      
      if (!details.successful) {
        return {
          verified: false,
          reason: `Transaction failed: ${details.status}`,
          details: details
        };
      }
      
      const contract = details.contractDetails;
      
      if (tokenContract) {
        // Verify TRC20 token payment
        if (contract.type !== 'Smart Contract Call') {
          return {
            verified: false,
            reason: 'Not a smart contract transaction',
            details: details
          };
        }
        
        // Would need to decode contract call data to verify TRC20 transfer
        // This is simplified for example
        return {
          verified: true,
          reason: 'TRC20 payment verification requires log analysis',
          details: details,
          note: 'Full TRC20 verification needs contract log parsing'
        };
        
      } else {
        // Verify TRX payment
        if (contract.type !== 'TRX Transfer') {
          return {
            verified: false,
            reason: 'Not a TRX transfer',
            details: details
          };
        }
        
        const amountMatch = contract.amount === expectedAmount;
        const recipientMatch = contract.to === expectedRecipient;
        
        return {
          verified: amountMatch && recipientMatch,
          reason: !amountMatch ? 'Amount mismatch' : 
                  !recipientMatch ? 'Recipient mismatch' : 
                  'Payment verified successfully',
          details: details,
          verification: {
            amountExpected: expectedAmount,
            amountReceived: contract.amount,
            recipientExpected: expectedRecipient,
            recipientActual: contract.to
          }
        };
      }
      
    } catch (error) {
      return {
        verified: false,
        reason: `Verification error: ${error.message}`,
        details: null
      };
    }
  }
}

// Usage examples
(async () => {
  try {
    const analyzer = new TronTransactionAnalyzer('YOUR_API_KEY');
    const txId = '2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5';
    
    // Get transaction details
    const details = await analyzer.getTransactionDetails(txId);
    console.log('Transaction details:', details);
    
    // Track transaction status
    const monitor = new TronTransactionMonitor('YOUR_API_KEY');
    
    monitor.monitor(txId, (result) => {
      if (result.found && result.successful) {
        console.log(`Payment confirmed: ${result.contractDetails.amountTRX} TRX`);
      } else {
        console.log(`Transaction issue: ${result.message || result.status}`);
      }
    });
    
    // Verify a payment
    const verifier = new TronPaymentVerifier('YOUR_API_KEY');
    const verification = await verifier.verifyPayment(
      txId,
      1000000, // 1 TRX in SUN
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN'
    );
    console.log('Payment verification:', verification);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
import time
import asyncio
from typing import Dict, List, Optional, Callable
from datetime import datetime

class TronTransactionAnalyzer:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def get_transaction_by_id(self, tx_id: str) -> Dict:
        """Get raw transaction data by ID"""
        url = f"{self.base_url}/wallet/gettransactionbyid"
        
        payload = {
            "value": tx_id,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def get_transaction_details(self, tx_id: str) -> Dict:
        """Get formatted transaction details with analysis"""
        try:
            transaction = self.get_transaction_by_id(tx_id)
            
            if not transaction.get('txID'):
                return {
                    'found': False,
                    'tx_id': tx_id,
                    'status': 'not_found',
                    'message': 'Transaction not found'
                }
            
            result = transaction.get('ret', [{}])[0]
            contract = transaction.get('raw_data', {}).get('contract', [{}])[0]
            
            return {
                'found': True,
                'tx_id': transaction['txID'],
                'status': result.get('contractRet', 'UNKNOWN'),
                'successful': result.get('contractRet') == 'SUCCESS',
                'block_number': transaction.get('blockNumber'),
                'block_timestamp': transaction.get('blockTimeStamp'),
                'fee': result.get('fee', 0),
                'energy_used': result.get('energy_usage', 0),
                'net_used': result.get('net_usage', 0),
                'contract_type': contract.get('type'),
                'contract_details': self._parse_contract(contract),
                'confirmations': transaction.get('confirmations', 0),
                'raw_transaction': transaction
            }
        except Exception as e:
            print(f"Error getting transaction details: {e}")
            raise
    
    def _parse_contract(self, contract: Dict) -> Optional[Dict]:
        """Parse contract details based on type"""
        if not contract.get('parameter', {}).get('value'):
            return None
        
        value = contract['parameter']['value']
        contract_type = contract.get('type')
        
        if contract_type == 'TransferContract':
            return {
                'type': 'TRX Transfer',
                'from': value.get('owner_address'),
                'to': value.get('to_address'),
                'amount': value.get('amount', 0),
                'amount_trx': (value.get('amount', 0) / 1_000_000)
            }
        elif contract_type == 'TriggerSmartContract':
            return {
                'type': 'Smart Contract Call',
                'caller': value.get('owner_address'),
                'contract': value.get('contract_address'),
                'data': value.get('data'),
                'call_value': value.get('call_value', 0)
            }
        elif contract_type == 'TransferAssetContract':
            return {
                'type': 'TRC10 Token Transfer',
                'from': value.get('owner_address'),
                'to': value.get('to_address'),
                'asset': value.get('asset_name'),
                'amount': value.get('amount', 0)
            }
        elif contract_type == 'FreezeBalanceContract':
            return {
                'type': 'Freeze TRX',
                'owner': value.get('owner_address'),
                'amount': value.get('frozen_balance', 0),
                'duration': value.get('frozen_duration', 0),
                'resource': value.get('resource')
            }
        elif contract_type == 'UnfreezeBalanceContract':
            return {
                'type': 'Unfreeze TRX',
                'owner': value.get('owner_address'),
                'resource': value.get('resource')
            }
        else:
            return {
                'type': contract_type,
                'details': value
            }
    
    def track_transaction_status(self, tx_id: str, timeout_ms: int = 60000) -> Dict:
        """Track transaction until confirmed or timeout"""
        start_time = time.time() * 1000
        check_interval = 3  # seconds
        
        while (time.time() * 1000) - start_time < timeout_ms:
            try:
                details = self.get_transaction_details(tx_id)
                
                if details['found']:
                    if details.get('block_number'):
                        return {
                            **details,
                            'tracking_status': 'confirmed',
                            'tracking_time': (time.time() * 1000) - start_time
                        }
                    else:
                        print('Transaction found in mempool, waiting for confirmation...')
                else:
                    print('Transaction not found, checking again...')
                
                time.sleep(check_interval)
                
            except Exception as e:
                print(f'Error tracking transaction: {e}')
                time.sleep(check_interval)
        
        return {
            'found': False,
            'tx_id': tx_id,
            'tracking_status': 'timeout',
            'tracking_time': timeout_ms,
            'message': 'Transaction tracking timeout'
        }

class TronPaymentVerifier:
    def __init__(self, api_key: str):
        self.analyzer = TronTransactionAnalyzer(api_key)
    
    def verify_payment(self, tx_id: str, expected_amount: int, 
                      expected_recipient: str, token_contract: str = None) -> Dict:
        """Verify payment transaction matches expected parameters"""
        try:
            details = self.analyzer.get_transaction_details(tx_id)
            
            if not details['found']:
                return {
                    'verified': False,
                    'reason': 'Transaction not found',
                    'details': None
                }
            
            if not details['successful']:
                return {
                    'verified': False,
                    'reason': f"Transaction failed: {details['status']}",
                    'details': details
                }
            
            contract = details['contract_details']
            
            if token_contract:
                # Verify TRC20 token payment
                if contract['type'] != 'Smart Contract Call':
                    return {
                        'verified': False,
                        'reason': 'Not a smart contract transaction',
                        'details': details
                    }
                
                # Full TRC20 verification would require log analysis
                return {
                    'verified': True,
                    'reason': 'TRC20 payment verification requires log analysis',
                    'details': details,
                    'note': 'Full TRC20 verification needs contract log parsing'
                }
            else:
                # Verify TRX payment
                if contract['type'] != 'TRX Transfer':
                    return {
                        'verified': False,
                        'reason': 'Not a TRX transfer',
                        'details': details
                    }
                
                amount_match = contract['amount'] == expected_amount
                recipient_match = contract['to'] == expected_recipient
                
                return {
                    'verified': amount_match and recipient_match,
                    'reason': 'Amount mismatch' if not amount_match else
                             'Recipient mismatch' if not recipient_match else
                             'Payment verified successfully',
                    'details': details,
                    'verification': {
                        'amount_expected': expected_amount,
                        'amount_received': contract['amount'],
                        'recipient_expected': expected_recipient,
                        'recipient_actual': contract['to']
                    }
                }
        except Exception as e:
            return {
                'verified': False,
                'reason': f'Verification error: {str(e)}',
                'details': None
            }

class TronTransactionBatchAnalyzer:
    def __init__(self, api_key: str):
        self.analyzer = TronTransactionAnalyzer(api_key)
    
    def analyze_multiple_transactions(self, tx_ids: List[str]) -> List[Dict]:
        """Analyze multiple transactions"""
        results = []
        
        for tx_id in tx_ids:
            try:
                details = self.analyzer.get_transaction_details(tx_id)
                results.append({
                    'tx_id': tx_id,
                    'success': True,
                    'details': details
                })
            except Exception as e:
                results.append({
                    'tx_id': tx_id,
                    'success': False,
                    'error': str(e)
                })
        
        return results
    
    def generate_transaction_report(self, tx_ids: List[str]) -> Dict:
        """Generate comprehensive report for multiple transactions"""
        results = self.analyze_multiple_transactions(tx_ids)
        
        successful_txs = [r for r in results if r['success'] and r['details']['found']]
        failed_txs = [r for r in results if r['success'] and not r['details']['successful']]
        not_found_txs = [r for r in results if r['success'] and not r['details']['found']]
        error_txs = [r for r in results if not r['success']]
        
        total_fees = sum(
            tx['details']['fee'] for tx in successful_txs 
            if tx['details']['successful']
        )
        
        total_energy = sum(
            tx['details']['energy_used'] for tx in successful_txs 
            if tx['details']['successful']
        )
        
        contract_types = {}
        for tx in successful_txs:
            if tx['details']['successful']:
                contract_type = tx['details']['contract_type']
                contract_types[contract_type] = contract_types.get(contract_type, 0) + 1
        
        return {
            'summary': {
                'total_analyzed': len(tx_ids),
                'successful': len(successful_txs),
                'failed': len(failed_txs),
                'not_found': len(not_found_txs),
                'errors': len(error_txs)
            },
            'costs': {
                'total_fees': total_fees,
                'total_energy_used': total_energy,
                'average_fee': total_fees / len(successful_txs) if successful_txs else 0
            },
            'contract_types': contract_types,
            'detailed_results': results,
            'generated_at': datetime.now().isoformat()
        }

# Usage examples
if __name__ == "__main__":
    analyzer = TronTransactionAnalyzer('YOUR_API_KEY')
    
    try:
        tx_id = '2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5'
        
        # Get transaction details
        details = analyzer.get_transaction_details(tx_id)
        print("Transaction details:")
        print(f"  Status: {details['status']}")
        print(f"  Successful: {details['successful']}")
        if details['contract_details']:
            print(f"  Type: {details['contract_details']['type']}")
            if 'amount_trx' in details['contract_details']:
                print(f"  Amount: {details['contract_details']['amount_trx']} TRX")
        
        # Verify payment
        verifier = TronPaymentVerifier('YOUR_API_KEY')
        verification = verifier.verify_payment(
            tx_id,
            1_000_000,  # 1 TRX in SUN
            'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN'
        )
        print(f"\nPayment verification: {verification['verified']}")
        print(f"Reason: {verification['reason']}")
        
        # Batch analysis
        batch_analyzer = TronTransactionBatchAnalyzer('YOUR_API_KEY')
        tx_list = [tx_id]  # Add more transaction IDs here
        
        report = batch_analyzer.generate_transaction_report(tx_list)
        print(f"\nBatch analysis:")
        print(f"  Total analyzed: {report['summary']['total_analyzed']}")
        print(f"  Successful: {report['summary']['successful']}")
        print(f"  Total fees: {report['costs']['total_fees']} SUN")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful TRX Transfer

```json
{
  "ret": [
    {
      "contractRet": "SUCCESS",
      "fee": 1100
    }
  ],
  "signature": [
    "c8f8f8e8d8c8b8a898887878686858484838281807060504030201..."
  ],
  "txID": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "amount": 1000000,
            "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
            "to_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"
          },
          "type_url": "type.googleapis.com/protocol.TransferContract"
        },
        "type": "TransferContract"
      }
    ],
    "ref_block_bytes": "4a7b",
    "ref_block_hash": "e15e44aa73bd9e15",
    "expiration": 1734567890000,
    "timestamp": 1734567830000
  },
  "blockNumber": 52895819,
  "blockTimeStamp": 1734567893000
}
```

### Failed Smart Contract Call

```json
{
  "ret": [
    {
      "contractRet": "REVERT",
      "fee": 5000
    }
  ],
  "signature": ["..."],
  "txID": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "data": "a9059cbb0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240",
            "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
            "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
          },
          "type_url": "type.googleapis.com/protocol.TriggerSmartContract"
        },
        "type": "TriggerSmartContract"
      }
    ],
    "ref_block_bytes": "4a7b",
    "ref_block_hash": "e15e44aa73bd9e15",
    "expiration": 1734567890000,
    "timestamp": 1734567830000
  },
  "blockNumber": 52895820,
  "blockTimeStamp": 1734567896000
}
```

### Transaction Not Found

```json
{}
```

## Common Use Cases

### 1. E-commerce Payment Tracking

```javascript
class EcommercePaymentTracker {
  constructor(apiKey) {
    this.analyzer = new TronTransactionAnalyzer(apiKey);
    this.paymentDatabase = new Map(); // Replace with real database
  }
  
  async trackOrderPayment(orderId, txId, expectedAmount, expectedRecipient) {
    try {
      // Store payment attempt
      this.paymentDatabase.set(orderId, {
        txId,
        expectedAmount,
        expectedRecipient,
        status: 'tracking',
        createdAt: Date.now()
      });
      
      // Track transaction
      const result = await this.analyzer.trackTransactionStatus(txId, 300000); // 5 min timeout
      
      if (result.trackingStatus === 'confirmed' && result.successful) {
        // Verify payment details
        const verification = await this.verifyOrderPayment(orderId, result);
        
        if (verification.verified) {
          await this.fulfillOrder(orderId);
          return { success: true, message: 'Payment confirmed and order fulfilled' };
        } else {
          await this.flagPaymentIssue(orderId, verification.reason);
          return { success: false, message: verification.reason };
        }
      } else {
        await this.handlePaymentFailure(orderId, result);
        return { success: false, message: 'Payment failed or timeout' };
      }
      
    } catch (error) {
      console.error(`Payment tracking error for order ${orderId}:`, error);
      throw error;
    }
  }
  
  async verifyOrderPayment(orderId, transactionResult) {
    const payment = this.paymentDatabase.get(orderId);
    const contract = transactionResult.contractDetails;
    
    if (contract.type !== 'TRX Transfer') {
      return { verified: false, reason: 'Not a TRX transfer' };
    }
    
    const amountMatch = contract.amount === payment.expectedAmount;
    const recipientMatch = contract.to === payment.expectedRecipient;
    
    return {
      verified: amountMatch && recipientMatch,
      reason: !amountMatch ? 'Payment amount mismatch' :
              !recipientMatch ? 'Payment recipient mismatch' :
              'Payment verified successfully'
    };
  }
  
  async fulfillOrder(orderId) {
    console.log(`✅ Fulfilling order ${orderId}`);
    // Implement order fulfillment logic
  }
  
  async flagPaymentIssue(orderId, reason) {
    console.log(`⚠️ Payment issue for order ${orderId}: ${reason}`);
    // Implement payment issue handling
  }
  
  async handlePaymentFailure(orderId, result) {
    console.log(`❌ Payment failed for order ${orderId}: ${result.message}`);
    // Implement payment failure handling
  }
}
```

### 2. Smart Contract Execution Monitor

```javascript
class SmartContractMonitor {
  constructor(apiKey) {
    this.analyzer = new TronTransactionAnalyzer(apiKey);
    this.contractAddresses = new Set();
  }
  
  addContract(address) {
    this.contractAddresses.add(address);
  }
  
  async monitorContractTransaction(txId) {
    try {
      const details = await this.analyzer.getTransactionDetails(txId);
      
      if (!details.found) {
        return { status: 'not_found', message: 'Transaction not found' };
      }
      
      if (details.contractDetails?.type !== 'Smart Contract Call') {
        return { status: 'not_contract', message: 'Not a smart contract transaction' };
      }
      
      const contractAddress = details.contractDetails.contract;
      
      if (!this.contractAddresses.has(contractAddress)) {
        return { status: 'not_monitored', message: 'Contract not in monitoring list' };
      }
      
      return {
        status: 'monitored',
        successful: details.successful,
        contractAddress,
        caller: details.contractDetails.caller,
        energyUsed: details.energyUsed,
        fee: details.fee,
        blockNumber: details.blockNumber,
        executionResult: details.status
      };
      
    } catch (error) {
      return { status: 'error', message: error.message };
    }
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/gettransactioninfobyid - Get TRON Receipt

# wallet/gettransactioninfobyid - Get TRON Receipt

Get detailed transaction information including receipt and logs by transaction ID.

## Endpoint

```
POST /wallet/gettransactioninfobyid
```

## Request Parameters

- `value` (`string, required`): Required parameter: Transaction ID (hex string)

## Request Example

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/gettransactioninfobyid \
      -H "Content-Type: application/json" \
      -d '{
        "value": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5"
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `id` - Transaction ID `fee` - Transaction fee in SUN `blockNumber` - Block height `blockTimeStamp` - Block timestamp `contractResult` - Contract execution result `contract_address` - Contract address (for contract creation) `receipt` - Transaction receipt with energy and bandwidth usage `log` - Transaction logs from smart contract events `result` - Transaction result ("SUCCESS" or error) `resMessage` - Result message (if any)

## Successful Response

```json
{
    "id": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5",
    "blockNumber": 76245444,
    "blockTimeStamp": 1759396656000,
    "contractResult": [
        "0000000000000000000000000000000000000000000000000000000000000000"
    ],
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "receipt": {
        "energy_usage": 64284,
        "origin_energy_usage": 1,
        "energy_usage_total": 64285,
        "net_usage": 345,
        "result": "SUCCESS",
        "energy_penalty_total": 49635
    },
    "log": [
        {
            "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
            "topics": [
                "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
                "000000000000000000000000d3048cf7d52e765643ad653bf8e17724b8887cdc",
                "00000000000000000000000083f5fda1a451a2c0d7739cb3b1891b103c13252f"
            ],
            "data": "0000000000000000000000000000000000000000000000000000000009896800"
        }
    ]
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/gettransactioninfobyid \
  -H "Content-Type: application/json" \
  -d '{
    "value": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5"
  }'
```

```javascript
// Get transaction receipt information
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/gettransactioninfobyid', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    value: '2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5'
  }),
});

const data = await response.json();
console.log(data);
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/gettransactioninfobyid"
payload = {
    "value": "2668be54c278d702eebde274a58cfae3ea50c72c76a885df48c6d456d7ec38b5"
}

response = requests.post(url, json=payload)
print(response.json())
```

## Use Cases

- **Transaction Confirmation**: Get detailed receipt after broadcasting
- **Event Monitoring**: Access smart contract event logs
- **Fee Tracking**: Monitor energy and bandwidth consumption
- **Debug Failures**: Analyze failed transaction reasons
- **DApp Integration**: Verify transaction results in applications

## Related Methods

- [wallet/gettransactionbyid](https://www.dwellir.com/docs/tron/wallet-gettransactionbyid) - Get basic transaction data
- [wallet/broadcasttransaction](https://www.dwellir.com/docs/tron/wallet-broadcasttransaction) - Broadcast signed transaction
- [wallet/triggersmartcontract](https://www.dwellir.com/docs/tron/wallet-triggersmartcontract) - Call smart contract function

---

## wallet/listwitnesses - Get Super Representatives

# wallet/listwitnesses - Get Super Representatives

Get list of all Super Representatives (witnesses) on the TRON network.

## Endpoint

```
POST /wallet/listwitnesses
```

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
# Get all witnesses
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses \
      -H "Content-Type: application/json" \
      -d '{}'

    # Get witnesses and filter top 5 by votes (using jq)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses \
      -H "Content-Type: application/json" \
      -d '{}' | jq '.witnesses | sort_by(-.voteCount) | .[0:5]'

    # Get specific witness info (using jq)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses \
      -H "Content-Type: application/json" \
      -d '{}' | jq '.witnesses[] | select(.address == "TYourWitnessAddress...")'
```

## Response Fields

- `result` (`OBJECT, required`): `address` - Witness address `voteCount` - Total votes received `url` - Witness website/information URL `totalProduced` - Total blocks produced `totalMissed` - Total blocks missed `latestBlockNum` - Latest block produced `latestSlotNum` - Latest slot number `isJobs` - Whether witness is active

## Successful Response

```json
{
  "witnesses": [
    {
      "address": "TSomeWitnessAddress...",
      "voteCount": 2847395820,
      "url": "https://tronsr.example.com",
      "totalProduced": 1847293,
      "totalMissed": 523,
      "latestBlockNum": 58234569,
      "latestSlotNum": 634829384,
      "isJobs": true
    },
    {
      "address": "TAnotherWitnessAddress...",
      "voteCount": 2539482910,
      "url": "https://anothersr.example.com",
      "totalProduced": 1693847,
      "totalMissed": 412,
      "latestBlockNum": 58234547,
      "latestSlotNum": 634829362,
      "isJobs": true
    }
  ]
}
```

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get all witnesses
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses \
  -H "Content-Type: application/json" \
  -d '{}'

# Get witnesses and filter top 5 by votes (using jq)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses \
  -H "Content-Type: application/json" \
  -d '{}' | jq '.witnesses | sort_by(-.voteCount) | .[0:5]'

# Get specific witness info (using jq)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses \
  -H "Content-Type: application/json" \
  -d '{}' | jq '.witnesses[] | select(.address == "TYourWitnessAddress...")'
```

```javascript
// Get all witnesses
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({}),
});

const data = await response.json();
const witnesses = data.witnesses || [];

// Sort by vote count
witnesses.sort((a, b) => b.voteCount - a.voteCount);

// Display top 27 Super Representatives
console.log('Top 27 Super Representatives:');
witnesses.slice(0, 27).forEach((witness, index) => {
  const votes = (witness.voteCount / 1000000).toFixed(2); // Convert to millions
  const reliability = witness.totalProduced > 0 
    ? ((witness.totalProduced / (witness.totalProduced + witness.totalMissed)) * 100).toFixed(2)
    : '0.00';
  
  console.log(`${index + 1}. ${witness.url}`);
  console.log(`   Votes: ${votes}M | Reliability: ${reliability}%`);
  console.log(`   Blocks: ${witness.totalProduced} produced, ${witness.totalMissed} missed`);
});

// Find specific witness
const myWitness = witnesses.find(w => w.address === 'TYourWitnessAddress...');
if (myWitness) {
  console.log(`\nYour witness ranking: #${witnesses.indexOf(myWitness) + 1}`);
}
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/listwitnesses"

response = requests.post(url, json={})
data = response.json()
witnesses = data.get('witnesses', [])

# Sort by votes
witnesses.sort(key=lambda x: x.get('voteCount', 0), reverse=True)

print("=== TRON Super Representatives ===\n")

# Display top 27 SRs (active block producers)
for i, witness in enumerate(witnesses[:27], 1):
    votes_millions = witness.get('voteCount', 0) / 1_000_000
    total_produced = witness.get('totalProduced', 0)
    total_missed = witness.get('totalMissed', 0)
    
    # Calculate reliability
    if total_produced + total_missed > 0:
        reliability = (total_produced / (total_produced + total_missed)) * 100
    else:
        reliability = 0
    
    print(f"{i}. {witness.get('url', 'Unknown')}")
    print(f"   Address: {witness.get('address', '')}")
    print(f"   Votes: {votes_millions:.2f}M")
    print(f"   Reliability: {reliability:.2f}%")
    print(f"   Blocks Produced: {total_produced:,}")
    print(f"   Blocks Missed: {total_missed:,}")
    print()

# Show SR candidates (rank 28+)
print("\n=== Super Representative Candidates ===")
for i, witness in enumerate(witnesses[27:35], 28):  # Show next 8 candidates
    votes_millions = witness.get('voteCount', 0) / 1_000_000
    print(f"{i}. {witness.get('url', 'Unknown')}: {votes_millions:.2f}M votes")
```

## Super Representative System

### SR Roles

- **Top 27**: Active block producers (Super Representatives)
- **28-127**: Super Representative Partners (receive rewards, no block production)
- **128+**: Candidates (no rewards)

### Voting Power

- 1 TRX = 1 Vote (when frozen for voting)
- Votes can be distributed among multiple SRs
- Votes remain until changed or TRX is unfrozen

### Block Production

- SRs take turns producing blocks
- 3-second block time
- Missed blocks affect reliability score

## Witness Analysis

```javascript
// Analyze witness performance
function analyzeWitnesses(witnesses) {
  const topSRs = witnesses.slice(0, 27);
  
  // Calculate network statistics
  const totalVotes = witnesses.reduce((sum, w) => sum + w.voteCount, 0);
  const totalBlocks = topSRs.reduce((sum, w) => sum + w.totalProduced, 0);
  const totalMissed = topSRs.reduce((sum, w) => sum + w.totalMissed, 0);
  
  // Find most reliable SRs
  const reliability = topSRs.map(w => ({
    url: w.url,
    address: w.address,
    reliability: w.totalProduced / (w.totalProduced + w.totalMissed) * 100
  })).sort((a, b) => b.reliability - a.reliability);
  
  // Calculate voting concentration
  const top5Votes = witnesses.slice(0, 5).reduce((sum, w) => sum + w.voteCount, 0);
  const votingConcentration = (top5Votes / totalVotes) * 100;
  
  return {
    totalVotes: totalVotes / 1000000, // In millions
    totalBlocks,
    totalMissed,
    networkReliability: (totalBlocks / (totalBlocks + totalMissed) * 100).toFixed(2),
    votingConcentration: votingConcentration.toFixed(2),
    mostReliable: reliability.slice(0, 5),
    leastReliable: reliability.slice(-5).reverse()
  };
}

// Monitor SR changes
async function monitorSRChanges(interval = 60000) {
  let previousSRs = [];
  
  setInterval(async () => {
    const response = await fetch(`${API_URL}/wallet/listwitnesses`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({})
    });
    
    const data = await response.json();
    const currentSRs = data.witnesses
      .sort((a, b) => b.voteCount - a.voteCount)
      .slice(0, 27)
      .map(w => w.address);
    
    // Check for changes
    if (previousSRs.length > 0) {
      const newSRs = currentSRs.filter(sr => !previousSRs.includes(sr));
      const removedSRs = previousSRs.filter(sr => !currentSRs.includes(sr));
      
      if (newSRs.length > 0 || removedSRs.length > 0) {
        console.log('SR List Changed!');
        if (newSRs.length > 0) console.log('New SRs:', newSRs);
        if (removedSRs.length > 0) console.log('Removed SRs:', removedSRs);
      }
    }
    
    previousSRs = currentSRs;
  }, interval);
}
```

## Best Practices

### 1. **Vote Distribution**

- Research SR reliability and contributions
- Consider distributing votes among multiple SRs
- Monitor SR performance regularly

### 2. **SR Selection Criteria**

- Block production reliability (>99.5%)
- Community contributions
- Technical infrastructure
- Reward sharing programs

### 3. **Monitoring**

- Track SR ranking changes
- Monitor block production stats
- Alert on significant vote shifts

## Use Cases

- **Voting Decisions**: Research SRs before voting
- **Network Monitoring**: Track SR performance and reliability
- **Reward Calculation**: Estimate voting rewards
- **Governance Participation**: Engage in network governance
- **SR Analytics**: Analyze voting patterns and network health

## Related Methods

- [wallet/votewitnessaccount](https://www.dwellir.com/docs/tron/wallet-votewitnessaccount) - Vote for Super Representatives
- [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount) - Check account votes
- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Freeze TRX for voting power

---

## wallet/triggerconstantcontract - Call View Func...

# wallet/triggerconstantcontract - Call View Func...

**Dwellir's TRON infrastructure** enables instant contract state queries without consuming energy or bandwidth.
Read smart contract data in real-time without transaction fees.

[Start querying contracts](https://dashboard.dwellir.com/register)

Execute smart contract view/pure functions without creating a blockchain transaction. Perfect for reading contract state, calculating values, or retrieving stored data.

## Use Cases

`wallet/triggerconstantcontract` is essential for:

- **Token Balance Queries** - Check TRC20 token balances
- **Price Feeds** - Read oracle price data
- **Game State** - Query game contract states
- **DeFi Positions** - Check liquidity pool shares
- **Contract Verification** - Test function outputs

## Request Parameters

- `contract_address` (`string, required`): Smart contract address (Base58 or Hex)
- `function_selector` (`string, required`): Function signature (e.g., "balanceOf(address)")
- `parameter` (`string, optional`): Encoded function parameters (hex)
- `owner_address` (`string, optional`): Address calling the function
- `call_value` (`number, optional`): TRX amount in SUN (for payable functions)
- `call_token_value` (`number, optional`): TRC10 token amount
- `token_id` (`number, optional`): TRC10 token ID
- `visible` (`boolean, optional`): Use Base58 format (default: true)

## Request Example

```json
{
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "function_selector": "balanceOf(address)",
  "parameter": "000000000000000000000000a614f803b6fd780986a42c78ec9c7f77e6ded13c",
  "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
  "visible": true
}
```

## Response Fields

- `result` (`object, required`): Execution result
- `result.result` (`boolean, required`): Whether execution succeeded
- `result.code` (`string, required`): Response code
- `result.message` (`string, required`): Error message if failed
- `energy_used` (`number, required`): Estimated energy consumption
- `constant_result` (`array, required`): Return values (hex encoded)
- `transaction` (`object, required`): Simulated transaction object

## Successful Response

```json
{
  "result": {
    "result": true,
    "code": "SUCCESS",
    "message": ""
  },
  "energy_used": 968,
  "constant_result": [
    "0000000000000000000000000000000000000000000000000000000005f5e100"
  ],
  "transaction": {
    "visible": true,
    "txID": "abc123...",
    "raw_data": {
      "contract": [
        {
          "parameter": {
            "value": {
              "data": "70a08231000000000000000000000000a614f803b6fd780986a42c78ec9c7f77e6ded13c",
              "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
              "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
            },
            "type_url": "type.googleapis.com/protocol.TriggerSmartContract"
          },
          "type": "TriggerSmartContract"
        }
      ],
      "ref_block_bytes": "7ac7",
      "ref_block_hash": "4d9bb8f8c9c59ac3",
      "expiration": 1702456849000,
      "timestamp": 1702456789000
    }
  }
}
```

## Error Responses

### Error 1

- Code: `CONTRACT_VALIDATE_ERROR`
- Description: Invalid contract address

### Error 2

- Code: `OUT_OF_ENERGY`
- Description: Insufficient energy for call

### Error 3

- Code: `REVERT`
- Description: Function reverted

### Error 4

- Code: `INVALID_METHOD`
- Description: Function doesn't exist

## Implementation Examples

cURL
JavaScript
Python

```bash
# Call TRC20 balanceOf function
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggerconstantcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "balanceOf(address)",
    "parameter": "000000000000000000000000a614f803b6fd780986a42c78ec9c7f77e6ded13c",
    "visible": true
  }'

# Get token name
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggerconstantcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "name()",
    "visible": true
  }'

# Get token symbol
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggerconstantcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "symbol()",
    "visible": true
  }'

# Get total supply
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggerconstantcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "totalSupply()",
    "visible": true
  }'

# Parse balance result with jq
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggerconstantcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "balanceOf(address)",
    "parameter": "000000000000000000000000a614f803b6fd780986a42c78ec9c7f77e6ded13c",
    "visible": true
  }' | jq '{
    success: .result.result,
    energy_used: .energy_used,
    balance_hex: .constant_result[0],
    balance_decimal: (.constant_result[0] | ltrimstr("0x") | 
                     if . == "" then "0" else . end | 
                     tonumber | tostring)
  }'

# Script to check multiple token balances
#!/bin/bash
API_KEY="YOUR_API_KEY"
USER_ADDRESS_HEX="000000000000000000000000a614f803b6fd780986a42c78ec9c7f77e6ded13c"

TOKENS=(
  "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t:USDT"
  "TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR:WTRX"
)

for token_info in "${TOKENS[@]}"; do
  IFS=':' read -r addr symbol <<< "$token_info"
  
  echo "Checking $symbol balance..."
  
  response=$(curl -s -X POST \
    "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/triggerconstantcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$addr\",
      \"function_selector\": \"balanceOf(address)\",
      \"parameter\": \"$USER_ADDRESS_HEX\",
      \"visible\": true
    }")
  
  balance=$(echo "$response" | jq -r '.constant_result[0]')
  
  if [ "$balance" != "null" ] && [ "$balance" != "" ]; then
    # Convert hex to decimal (simplified)
    echo "  Raw: $balance"
  else
    echo "  Error or zero balance"
  fi
  echo ""
done
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Basic contract call
async function callContractView(contractAddress, functionSelector, parameter) {
  const response = await fetch(`${TRON_API}/wallet/triggerconstantcontract`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      contract_address: contractAddress,
      function_selector: functionSelector,
      parameter: parameter,
      visible: true
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  return await response.json();
}

// TRC20 Token Interface
class TRC20Contract {
  constructor(apiKey, contractAddress) {
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
    this.contractAddress = contractAddress;
    this.decimals = null;
  }
  
  async callView(functionSelector, parameter = '') {
    const response = await fetch(`${this.apiUrl}/wallet/triggerconstantcontract`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        contract_address: this.contractAddress,
        function_selector: functionSelector,
        parameter: parameter,
        visible: true
      })
    });
    
    const result = await response.json();
    
    if (!result.result?.result) {
      throw new Error(result.result?.message || 'Contract call failed');
    }
    
    return result.constant_result?.[0] || '0x';
  }
  
  // Encode address for parameter
  encodeAddress(address) {
    // Remove 'T' prefix and decode base58 to hex
    // This is simplified - actual implementation needs base58 decoder
    if (address.startsWith('T')) {
      // Convert Base58 to hex (placeholder)
      const hex = address.substring(1).toLowerCase();
      return '000000000000000000000000' + hex.padEnd(40, '0').substring(0, 40);
    }
    return address;
  }
  
  // Decode uint256 result
  decodeUint256(hex) {
    if (!hex || hex === '0x') return '0';
    const cleaned = hex.replace('0x', '');
    return BigInt('0x' + cleaned).toString();
  }
  
  // Get token balance
  async balanceOf(address) {
    const parameter = this.encodeAddress(address);
    const result = await this.callView('balanceOf(address)', parameter);
    const balance = this.decodeUint256(result);
    
    // Get decimals if not cached
    if (this.decimals === null) {
      this.decimals = await this.getDecimals();
    }
    
    return {
      raw: balance,
      formatted: this.formatUnits(balance, this.decimals)
    };
  }
  
  // Get token decimals
  async getDecimals() {
    const result = await this.callView('decimals()');
    return parseInt(this.decodeUint256(result));
  }
  
  // Get token symbol
  async symbol() {
    const result = await this.callView('symbol()');
    return this.decodeString(result);
  }
  
  // Get token name
  async name() {
    const result = await this.callView('name()');
    return this.decodeString(result);
  }
  
  // Get total supply
  async totalSupply() {
    const result = await this.callView('totalSupply()');
    const supply = this.decodeUint256(result);
    
    if (this.decimals === null) {
      this.decimals = await this.getDecimals();
    }
    
    return {
      raw: supply,
      formatted: this.formatUnits(supply, this.decimals)
    };
  }
  
  // Get allowance
  async allowance(owner, spender) {
    const parameter = this.encodeAddress(owner) + this.encodeAddress(spender);
    const result = await this.callView('allowance(address,address)', parameter);
    return this.decodeUint256(result);
  }
  
  // Format units with decimals
  formatUnits(value, decimals) {
    const divisor = BigInt(10) ** BigInt(decimals);
    const quotient = BigInt(value) / divisor;
    const remainder = BigInt(value) % divisor;
    
    if (remainder === 0n) {
      return quotient.toString();
    }
    
    const remainderStr = remainder.toString().padStart(decimals, '0');
    const trimmed = remainderStr.replace(/0+$/, '');
    
    return `${quotient}.${trimmed}`;
  }
  
  // Decode string from hex
  decodeString(hex) {
    if (!hex || hex === '0x') return '';
    
    try {
      // Remove 0x prefix
      const cleaned = hex.replace('0x', '');
      
      // Skip first 64 chars (offset) and next 64 chars (length)
      const dataStart = 128;
      const lengthHex = cleaned.substring(64, 128);
      const length = parseInt(lengthHex, 16) * 2;
      
      const stringHex = cleaned.substring(dataStart, dataStart + length);
      
      // Convert hex to string
      let result = '';
      for (let i = 0; i < stringHex.length; i += 2) {
        result += String.fromCharCode(parseInt(stringHex.substr(i, 2), 16));
      }
      
      return result;
    } catch (error) {
      console.error('String decode error:', error);
      return '';
    }
  }
}

// DeFi Protocol Reader
class DeFiProtocolReader {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }
  
  async readContract(address, method, params = '') {
    const response = await fetch(`${this.apiUrl}/wallet/triggerconstantcontract`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        contract_address: address,
        function_selector: method,
        parameter: params,
        visible: true
      })
    });
    
    return await response.json();
  }
  
  // Read lending protocol data
  async getLendingPosition(protocol, userAddress) {
    const params = this.encodeAddress(userAddress);
    
    const [
      supplyBalance,
      borrowBalance,
      collateralRatio
    ] = await Promise.all([
      this.readContract(protocol, 'getSupplyBalance(address)', params),
      this.readContract(protocol, 'getBorrowBalance(address)', params),
      this.readContract(protocol, 'getCollateralRatio(address)', params)
    ]);
    
    return {
      supplied: this.decodeResult(supplyBalance),
      borrowed: this.decodeResult(borrowBalance),
      collateralRatio: this.decodeResult(collateralRatio),
      healthFactor: this.calculateHealthFactor(
        this.decodeResult(supplyBalance),
        this.decodeResult(borrowBalance),
        this.decodeResult(collateralRatio)
      )
    };
  }
  
  // Read DEX pool data
  async getPoolInfo(poolAddress) {
    const [
      reserves,
      totalSupply,
      fee
    ] = await Promise.all([
      this.readContract(poolAddress, 'getReserves()'),
      this.readContract(poolAddress, 'totalSupply()'),
      this.readContract(poolAddress, 'fee()')
    ]);
    
    const reserveData = this.decodeReserves(reserves.constant_result?.[0]);
    
    return {
      token0Reserve: reserveData.reserve0,
      token1Reserve: reserveData.reserve1,
      totalSupply: this.decodeResult(totalSupply),
      fee: this.decodeResult(fee),
      price: this.calculatePrice(reserveData.reserve0, reserveData.reserve1)
    };
  }
  
  // Read oracle price
  async getOraclePrice(oracleAddress, pairId) {
    const params = this.encodeUint256(pairId);
    const result = await this.readContract(
      oracleAddress,
      'getLatestPrice(uint256)',
      params
    );
    
    const price = this.decodeResult(result);
    
    return {
      price: price,
      formatted: this.formatPrice(price),
      timestamp: Date.now()
    };
  }
  
  encodeAddress(address) {
    // Simplified encoding
    return '000000000000000000000000' + address.replace('T', '').substring(0, 40);
  }
  
  encodeUint256(value) {
    const hex = BigInt(value).toString(16);
    return hex.padStart(64, '0');
  }
  
  decodeResult(response) {
    const hex = response.constant_result?.[0] || '0x0';
    return BigInt('0x' + hex.replace('0x', '')).toString();
  }
  
  decodeReserves(hex) {
    if (!hex) return { reserve0: '0', reserve1: '0' };
    
    const cleaned = hex.replace('0x', '');
    const reserve0 = BigInt('0x' + cleaned.substring(0, 64)).toString();
    const reserve1 = BigInt('0x' + cleaned.substring(64, 128)).toString();
    
    return { reserve0, reserve1 };
  }
  
  calculatePrice(reserve0, reserve1) {
    if (reserve1 === '0') return '0';
    return (BigInt(reserve0) * BigInt(1e18) / BigInt(reserve1)).toString();
  }
  
  calculateHealthFactor(supply, borrow, ratio) {
    if (borrow === '0') return 'Infinite';
    const factor = (BigInt(supply) * BigInt(ratio)) / BigInt(borrow);
    return (factor / BigInt(100)).toString();
  }
  
  formatPrice(price) {
    const priceNum = Number(price) / 1e18;
    return priceNum.toFixed(6);
  }
}

// Usage examples
(async () => {
  try {
    // USDT Contract
    const usdt = new TRC20Contract('YOUR_API_KEY', 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t');
    
    // Get token info
    const [name, symbol, decimals, totalSupply] = await Promise.all([
      usdt.name(),
      usdt.symbol(),
      usdt.getDecimals(),
      usdt.totalSupply()
    ]);
    
    console.log(`Token: ${name} (${symbol})`);
    console.log(`Decimals: ${decimals}`);
    console.log(`Total Supply: ${totalSupply.formatted}`);
    
    // Check balance
    const balance = await usdt.balanceOf('TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN');
    console.log(`Balance: ${balance.formatted} ${symbol}`);
    
    // DeFi Protocol Reader
    const defi = new DeFiProtocolReader('YOUR_API_KEY');
    
    // Read lending position
    const position = await defi.getLendingPosition(
      'TLendingProtocolAddress',
      'TUserAddress'
    );
    console.log('Lending Position:', position);
    
    // Get oracle price
    const price = await defi.getOraclePrice('TOracleAddress', 1);
    console.log(`Oracle Price: $${price.formatted}`);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
from typing import Dict, Optional, Any
from web3 import Web3

class TronContractReader:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {'Content-Type': 'application/json'}
        self.w3 = Web3()  # For encoding/decoding
    
    def trigger_constant_contract(
        self,
        contract_address: str,
        function_selector: str,
        parameter: str = '',
        owner_address: Optional[str] = None,
        visible: bool = True
    ) -> Dict:
        """
        Call a view/pure function on a smart contract
        """
        url = f"{self.base_url}/wallet/triggerconstantcontract"
        
        payload = {
            "contract_address": contract_address,
            "function_selector": function_selector,
            "parameter": parameter,
            "visible": visible
        }
        
        if owner_address:
            payload["owner_address"] = owner_address
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def encode_address(self, address: str) -> str:
        """
        Encode TRON address for function parameter
        """
        # Remove T prefix for Base58 addresses
        if address.startswith('T'):
            # Simplified - actual implementation needs base58 decoder
            hex_addr = address[1:].lower()[:40].zfill(40)
            return '000000000000000000000000' + hex_addr
        return address.zfill(64)
    
    def encode_uint256(self, value: int) -> str:
        """
        Encode integer as uint256
        """
        return format(value, '064x')
    
    def decode_uint256(self, hex_value: str) -> int:
        """
        Decode uint256 from hex
        """
        if not hex_value or hex_value == '0x':
            return 0
        cleaned = hex_value.replace('0x', '')
        return int(cleaned, 16)
    
    def decode_address(self, hex_value: str) -> str:
        """
        Decode address from hex result
        """
        if not hex_value or len(hex_value) < 64:
            return ''
        cleaned = hex_value.replace('0x', '')
        # Get last 40 characters (20 bytes)
        return '41' + cleaned[-40:]
    
    def decode_string(self, hex_value: str) -> str:
        """
        Decode string from hex result
        """
        if not hex_value or hex_value == '0x':
            return ''
        
        try:
            cleaned = hex_value.replace('0x', '')
            
            # Skip offset (first 32 bytes)
            # Read length (next 32 bytes)
            if len(cleaned) < 128:
                return ''
            
            length = int(cleaned[64:128], 16) * 2
            string_hex = cleaned[128:128 + length]
            
            # Convert hex to string
            result = bytes.fromhex(string_hex).decode('utf-8')
            return result.rstrip('\x00')
        except:
            return ''
    
    def decode_bool(self, hex_value: str) -> bool:
        """
        Decode boolean from hex result
        """
        return self.decode_uint256(hex_value) != 0

class TRC20Token(TronContractReader):
    """
    TRC20 Token Interface
    """
    def __init__(self, api_key: str, contract_address: str):
        super().__init__(api_key)
        self.contract_address = contract_address
        self._decimals = None
        self._symbol = None
        self._name = None
    
    def call_view(self, function: str, params: str = '') -> str:
        """
        Call a view function on the token contract
        """
        result = self.trigger_constant_contract(
            self.contract_address,
            function,
            params
        )
        
        if not result.get('result', {}).get('result'):
            raise Exception(f"Contract call failed: {result.get('result', {}).get('message')}")
        
        return result.get('constant_result', ['0x'])[0]
    
    def balance_of(self, address: str) -> Dict:
        """
        Get token balance of an address
        """
        params = self.encode_address(address)
        result = self.call_view('balanceOf(address)', params)
        raw_balance = self.decode_uint256(result)
        
        decimals = self.decimals()
        formatted = self.format_units(raw_balance, decimals)
        
        return {
            'raw': str(raw_balance),
            'formatted': formatted,
            'decimals': decimals
        }
    
    def decimals(self) -> int:
        """
        Get token decimals (cached)
        """
        if self._decimals is None:
            result = self.call_view('decimals()')
            self._decimals = self.decode_uint256(result)
        return self._decimals
    
    def symbol(self) -> str:
        """
        Get token symbol (cached)
        """
        if self._symbol is None:
            result = self.call_view('symbol()')
            self._symbol = self.decode_string(result)
        return self._symbol
    
    def name(self) -> str:
        """
        Get token name (cached)
        """
        if self._name is None:
            result = self.call_view('name()')
            self._name = self.decode_string(result)
        return self._name
    
    def total_supply(self) -> Dict:
        """
        Get total supply
        """
        result = self.call_view('totalSupply()')
        raw_supply = self.decode_uint256(result)
        
        decimals = self.decimals()
        formatted = self.format_units(raw_supply, decimals)
        
        return {
            'raw': str(raw_supply),
            'formatted': formatted
        }
    
    def allowance(self, owner: str, spender: str) -> Dict:
        """
        Get allowance
        """
        params = self.encode_address(owner) + self.encode_address(spender)
        result = self.call_view('allowance(address,address)', params)
        raw_allowance = self.decode_uint256(result)
        
        decimals = self.decimals()
        formatted = self.format_units(raw_allowance, decimals)
        
        return {
            'raw': str(raw_allowance),
            'formatted': formatted
        }
    
    def format_units(self, value: int, decimals: int) -> str:
        """
        Format value with decimals
        """
        if decimals == 0:
            return str(value)
        
        divisor = 10 ** decimals
        quotient = value // divisor
        remainder = value % divisor
        
        if remainder == 0:
            return str(quotient)
        
        remainder_str = str(remainder).zfill(decimals).rstrip('0')
        return f"{quotient}.{remainder_str}"

class DeFiProtocol(TronContractReader):
    """
    DeFi Protocol Reader
    """
    def __init__(self, api_key: str):
        super().__init__(api_key)
    
    def get_pool_reserves(self, pool_address: str) -> Dict:
        """
        Get DEX pool reserves
        """
        result = self.trigger_constant_contract(
            pool_address,
            'getReserves()'
        )
        
        if not result.get('constant_result'):
            return {'reserve0': 0, 'reserve1': 0}
        
        hex_result = result['constant_result'][0].replace('0x', '')
        
        reserve0 = int(hex_result[0:64], 16)
        reserve1 = int(hex_result[64:128], 16)
        
        return {
            'reserve0': reserve0,
            'reserve1': reserve1,
            'price': self.calculate_price(reserve0, reserve1),
            'liquidity': (reserve0 * reserve1) ** 0.5
        }
    
    def get_lending_position(self, protocol: str, user: str) -> Dict:
        """
        Get lending protocol position
        """
        params = self.encode_address(user)
        
        # Get multiple values in parallel
        supply_result = self.trigger_constant_contract(
            protocol, 'getSupplyBalance(address)', params
        )
        borrow_result = self.trigger_constant_contract(
            protocol, 'getBorrowBalance(address)', params
        )
        
        supply = self.decode_uint256(supply_result.get('constant_result', ['0'])[0])
        borrow = self.decode_uint256(borrow_result.get('constant_result', ['0'])[0])
        
        return {
            'supplied': supply,
            'borrowed': borrow,
            'net_position': supply - borrow,
            'utilization': (borrow / supply * 100) if supply > 0 else 0
        }
    
    def get_oracle_price(self, oracle: str, pair_id: int) -> Dict:
        """
        Get price from oracle
        """
        params = self.encode_uint256(pair_id)
        result = self.trigger_constant_contract(
            oracle,
            'getLatestPrice(uint256)',
            params
        )
        
        price = self.decode_uint256(result.get('constant_result', ['0'])[0])
        
        return {
            'price': price,
            'formatted': price / 1e18,  # Assuming 18 decimals
            'pair_id': pair_id
        }
    
    def calculate_price(self, reserve0: int, reserve1: int) -> float:
        """
        Calculate price from reserves
        """
        if reserve1 == 0:
            return 0
        return reserve0 / reserve1

class MultiContractReader:
    """
    Read multiple contracts efficiently
    """
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.reader = TronContractReader(api_key)
    
    def batch_token_info(self, token_addresses: list) -> list:
        """
        Get info for multiple tokens
        """
        results = []
        
        for address in token_addresses:
            try:
                token = TRC20Token(self.api_key, address)
                info = {
                    'address': address,
                    'name': token.name(),
                    'symbol': token.symbol(),
                    'decimals': token.decimals(),
                    'total_supply': token.total_supply()
                }
                results.append(info)
            except Exception as e:
                results.append({
                    'address': address,
                    'error': str(e)
                })
        
        return results
    
    def portfolio_balance(self, user: str, token_list: list) -> Dict:
        """
        Get user's token portfolio
        """
        portfolio = []
        
        for token_addr in token_list:
            try:
                token = TRC20Token(self.api_key, token_addr)
                balance = token.balance_of(user)
                
                if int(balance['raw']) > 0:
                    portfolio.append({
                        'token': token_addr,
                        'symbol': token.symbol(),
                        'balance': balance['formatted'],
                        'raw': balance['raw']
                    })
            except:
                continue
        
        return {
            'address': user,
            'tokens': portfolio,
            'token_count': len(portfolio)
        }

# Usage examples
if __name__ == "__main__":
    # Initialize clients
    reader = TronContractReader('YOUR_API_KEY')
    
    # USDT Token
    usdt = TRC20Token('YOUR_API_KEY', 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t')
    
    try:
        # Get token info
        print(f"Token: {usdt.name()} ({usdt.symbol()})")
        print(f"Decimals: {usdt.decimals()}")
        
        total_supply = usdt.total_supply()
        print(f"Total Supply: {total_supply['formatted']} {usdt.symbol()}")
        
        # Check balance
        address = 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN'
        balance = usdt.balance_of(address)
        print(f"\nBalance of {address[:10]}...")
        print(f"  {balance['formatted']} {usdt.symbol()}")
        
        # DeFi operations
        defi = DeFiProtocol('YOUR_API_KEY')
        
        # Get pool reserves (example)
        pool = 'TPoolAddress'
        reserves = defi.get_pool_reserves(pool)
        print(f"\nPool Reserves:")
        print(f"  Reserve0: {reserves['reserve0']}")
        print(f"  Reserve1: {reserves['reserve1']}")
        print(f"  Price: {reserves['price']:.6f}")
        
        # Multi-contract reader
        multi = MultiContractReader('YOUR_API_KEY')
        
        # Check multiple tokens
        tokens = [
            'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',  # USDT
            'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR'   # WTRX
        ]
        
        token_info = multi.batch_token_info(tokens)
        print(f"\nToken Information:")
        for info in token_info:
            if 'error' not in info:
                print(f"  {info['symbol']}: {info['total_supply']['formatted']}")
        
        # Get portfolio
        portfolio = multi.portfolio_balance(address, tokens)
        print(f"\nPortfolio for {address[:10]}...")
        for holding in portfolio['tokens']:
            print(f"  {holding['symbol']}: {holding['balance']}")
            
    except Exception as e:
        print(f"Error: {e}")
```

## Common Use Cases

### 1. Token Balance Checker

```javascript
async function checkTokenBalance(tokenAddress, userAddress) {
  const token = new TRC20Contract('API_KEY', tokenAddress);
  
  try {
    const [symbol, decimals, balance] = await Promise.all([
      token.symbol(),
      token.getDecimals(),
      token.balanceOf(userAddress)
    ]);
    
    return {
      token: symbol,
      balance: balance.formatted,
      decimals: decimals,
      hasBalance: BigInt(balance.raw) > 0n
    };
  } catch (error) {
    return {
      error: 'Failed to fetch token data',
      details: error.message
    };
  }
}
```

### 2. DEX Price Monitor

```javascript
async function monitorDexPrice(poolAddress) {
  const getPrice = async () => {
    const result = await callContractView(
      poolAddress,
      'getReserves()'
    );
    
    const reserves = parseReserves(result.constant_result[0]);
    return calculatePrice(reserves.token0, reserves.token1);
  };
  
  return setInterval(async () => {
    const price = await getPrice();
    console.log(`Current price: ${price}`);
  }, 10000); // Check every 10 seconds
}
```

### 3. Multi-Call Pattern

```javascript
async function getCompleteTokenInfo(tokenAddress) {
  const functions = [
    'name()',
    'symbol()',
    'decimals()',
    'totalSupply()'
  ];
  
  const results = await Promise.all(
    functions.map(fn => 
      callContractView(tokenAddress, fn)
    )
  );
  
  return {
    name: decodeString(results[0].constant_result[0]),
    symbol: decodeString(results[1].constant_result[0]),
    decimals: decodeUint256(results[2].constant_result[0]),
    totalSupply: decodeUint256(results[3].constant_result[0])
  };
}
```

## Best Practices

1. **Cache Results** - Cache view function results appropriately
2. **Batch Calls** - Group multiple calls for efficiency
3. **Handle Errors** - Always check result.result for success
4. **Estimate Energy** - Monitor energy\_used for optimization
5. **Validate Input** - Ensure parameters are properly encoded

## Related Methods

- [wallet/triggersmartcontract](https://www.dwellir.com/docs/tron/wallet-triggersmartcontract) - Execute state-changing functions
- [wallet/getcontract](https://www.dwellir.com/docs/tron/wallet-getcontract) - Get contract information
- [wallet/estimateenergy](https://www.dwellir.com/docs/tron/wallet-estimateenergy) - Estimate energy consumption

***

*Need help? Contact [support](mailto:support@dwellir.com) or visit our [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/triggersmartcontract - Execute TRON Smar...

# wallet/triggersmartcontract - Execute TRON Smar...

**Dwellir's TRON endpoints** execute smart contract calls in under 30ms with comprehensive error handling.
Build powerful DeFi and Web3 applications with our optimized contract interaction API.

[Start building with smart contracts](https://dashboard.dwellir.com/register)

Executes smart contract functions on the TRON network. Use this method to call contract functions, read contract state, and interact with TRC20/TRC721 tokens.

## When to Use This Method

`wallet/triggersmartcontract` is essential for:

- **TRC20 Token Operations** - Transfer, approve, check balances
- **DeFi Protocol Interactions** - Swap, stake, lend, borrow
- **NFT Operations** - Mint, transfer, query TRC721 tokens
- **Contract State Queries** - Read public variables and view functions
- **Smart Contract Execution** - Call payable and non-payable functions

## Request Parameters

- `contract_address` (`string, required`): Smart contract address in Base58 format Example: `"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"` (USDT)
- `function_selector` (`string, required`): Function signature to call Example: `"balanceOf(address)"`, `"transfer(address,uint256)"`
- `parameter` (`string, optional`): Hex-encoded function parameters Example: `"0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863"`
- `owner_address` (`string, required`): Address calling the contract Example: `"TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh"`
- `call_value` (`integer, optional`): TRX amount to send (in SUN) for payable functions Default: `0`
- `visible` (`boolean, optional`): `true` - Use Base58 address format `false` - Use hex address format

## Request Example

```json
{
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "function_selector": "balanceOf(address)",
  "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863",
  "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
  "visible": true
}
```

## Response Fields

- `result` (`OBJECT, required`): `result` - Execution success/failure `constant_result` - Array of result data (for view functions) `transaction` - Transaction object (for state-changing functions) `energy_used` - Energy consumed `energy_penalty` - Additional energy cost `result_message` - Error message (if failed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {}
}
```

## Error Responses

### Error 1

- Description: Contract execution reverted

### Error 2

- Description: Insufficient energy for execution

### Error 3

- Description: Malformed contract address

### Error 4

- Description: Function doesn't exist

### Error 5

- Description: Parameter encoding failed

## Implementation Examples

cURL
JavaScript
Python

```bash
# Get TRC20 token balance (USDT)
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggersmartcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "balanceOf(address)",
    "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863",
    "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "visible": true
  }'

# Get token symbol
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggersmartcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "symbol()",
    "owner_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "visible": true
  }'

# Get token decimals
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggersmartcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "decimals()",
    "owner_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "visible": true
  }'

# Create TRC20 transfer transaction
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggersmartcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "transfer(address,uint256)",
    "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240",
    "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
    "visible": true
  }'

# Parse and format token balance
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/triggersmartcontract" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "balanceOf(address)",
    "parameter": "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863",
    "owner_address": "TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN",
    "visible": true
  }' | jq '{
    success: .result.result,
    balance_hex: .constant_result[0],
    balance_decimal: (.constant_result[0] | if . then (. | tonumber) else 0 end),
    energy_used: .energy_used
  }'

# Batch token information script
#!/bin/bash
API_KEY="YOUR_API_KEY"
CONTRACT_ADDRESS="TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"  # USDT
WALLET_ADDRESS="TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN"

echo "Fetching token information for $CONTRACT_ADDRESS..."

# Function to call smart contract
call_contract() {
  local function_selector=$1
  local parameters=${2:-""}
  local owner_address=${3:-$CONTRACT_ADDRESS}
  
  curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/triggersmartcontract" \
    -H "Content-Type: application/json" \
    -d "{
      \"contract_address\": \"$CONTRACT_ADDRESS\",
      \"function_selector\": \"$function_selector\",
      \"parameter\": \"$parameters\",
      \"owner_address\": \"$owner_address\",
      \"visible\": true
    }"
}

# Convert address to parameter format (simplified)
address_to_param() {
  local address=$1
  # This is a simplified conversion - use proper tools in production
  echo "0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863"
}

# Get token name
echo "Getting token name..."
NAME_RESULT=$(call_contract "name()")
echo "Name result: $NAME_RESULT" | jq '.constant_result[0]'

# Get token symbol
echo "Getting token symbol..."
SYMBOL_RESULT=$(call_contract "symbol()")
echo "Symbol result: $SYMBOL_RESULT" | jq '.constant_result[0]'

# Get token decimals
echo "Getting token decimals..."
DECIMALS_RESULT=$(call_contract "decimals()")
DECIMALS=$(echo "$DECIMALS_RESULT" | jq -r '.constant_result[0]' | xargs printf "%d")
echo "Decimals: $DECIMALS"

# Get total supply
echo "Getting total supply..."
SUPPLY_RESULT=$(call_contract "totalSupply()")
SUPPLY_HEX=$(echo "$SUPPLY_RESULT" | jq -r '.constant_result[0]')
SUPPLY_DECIMAL=$(printf "%d" "0x$SUPPLY_HEX")
echo "Total supply: $SUPPLY_DECIMAL"

# Get balance for specific address
echo "Getting balance for $WALLET_ADDRESS..."
ADDRESS_PARAM=$(address_to_param "$WALLET_ADDRESS")
BALANCE_RESULT=$(call_contract "balanceOf(address)" "$ADDRESS_PARAM" "$WALLET_ADDRESS")
BALANCE_HEX=$(echo "$BALANCE_RESULT" | jq -r '.constant_result[0]')
BALANCE_DECIMAL=$(printf "%d" "0x$BALANCE_HEX")
echo "Balance: $BALANCE_DECIMAL"

# Calculate formatted balance
if [ "$DECIMALS" -gt 0 ]; then
  FORMATTED_BALANCE=$(echo "scale=6; $BALANCE_DECIMAL / (10^$DECIMALS)" | bc -l)
  echo "Formatted balance: $FORMATTED_BALANCE"
fi

# DeFi protocol interaction example
query_defi_pool() {
  local defi_contract=$1
  local pool_id=$2
  local user_address=$3
  
  echo "Querying DeFi pool $pool_id for user $user_address..."
  
  # Pool info
  POOL_ID_HEX=$(printf "%064x" "$pool_id")
  POOL_RESULT=$(call_contract "poolInfo(uint256)" "$POOL_ID_HEX" "$defi_contract")
  echo "Pool info: $POOL_RESULT" | jq '.constant_result[0]'
  
  # User info
  USER_PARAM="${POOL_ID_HEX}$(address_to_param "$user_address")"
  USER_RESULT=$(call_contract "userInfo(uint256,address)" "$USER_PARAM" "$user_address")
  echo "User info: $USER_RESULT" | jq '.constant_result[0]'
}

# Multi-token balance checker
check_multiple_tokens() {
  local wallet_address=$1
  
  # Define popular TRON tokens
  declare -A TOKENS=(
    ["USDT"]="TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
    ["USDC"]="TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8"
    ["JST"]="TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9"
    ["WTRX"]="TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR"
  )
  
  echo "Checking token balances for $wallet_address..."
  echo "=========================================="
  
  for token_name in "${!TOKENS[@]}"; do
    local token_address="${TOKENS[$token_name]}"
    echo "Checking $token_name ($token_address)..."
    
    # Get balance
    local address_param=$(address_to_param "$wallet_address")
    local balance_result=$(curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/triggersmartcontract" \
      -H "Content-Type: application/json" \
      -d "{
        \"contract_address\": \"$token_address\",
        \"function_selector\": \"balanceOf(address)\",
        \"parameter\": \"$address_param\",
        \"owner_address\": \"$wallet_address\",
        \"visible\": true
      }")
    
    local balance_hex=$(echo "$balance_result" | jq -r '.constant_result[0] // "0"')
    local balance_decimal=$(printf "%d" "0x$balance_hex" 2>/dev/null || echo "0")
    
    echo "$token_name balance: $balance_decimal"
    echo ""
  done
}

# Usage examples
case "${1:-info}" in
  "info")
    # Default: show token info
    ;;
  "balance")
    check_multiple_tokens "$2"
    ;;
  "defi")
    query_defi_pool "$2" "$3" "$4"
    ;;
  *)
    echo "Usage: $0 {info|balance WALLET_ADDRESS|defi CONTRACT_ADDRESS POOL_ID USER_ADDRESS}"
    ;;
esac
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Smart contract interaction helper
class TronSmartContract {
  constructor(apiKey, contractAddress) {
    this.apiKey = apiKey;
    this.contractAddress = contractAddress;
    this.apiUrl = `${TRON_API}`;
  }
  
  async call(functionSelector, parameters = '', ownerAddress, callValue = 0) {
    const response = await fetch(`${this.apiUrl}/wallet/triggersmartcontract`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        contract_address: this.contractAddress,
        function_selector: functionSelector,
        parameter: parameters,
        owner_address: ownerAddress,
        call_value: callValue,
        visible: true
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return await response.json();
  }
  
  // Helper method to encode address parameter
  encodeAddress(address) {
    // Convert Base58 to hex and pad to 64 characters
    const hexAddress = this.base58ToHex(address);
    return hexAddress.toLowerCase().padStart(64, '0');
  }
  
  // Helper method to encode uint256 parameter
  encodeUint256(value) {
    return BigInt(value).toString(16).padStart(64, '0');
  }
  
  // Helper method to decode result
  decodeResult(hexResult, type = 'uint256') {
    if (!hexResult || hexResult === '0x') return null;
    
    // Remove 0x prefix if present
    const cleanHex = hexResult.replace(/^0x/, '');
    
    switch (type) {
      case 'uint256':
        return BigInt('0x' + cleanHex).toString();
      case 'address':
        // Extract address from padded hex
        const addressHex = cleanHex.slice(-40);
        return this.hexToBase58(addressHex);
      case 'bool':
        return cleanHex === '1' || cleanHex.endsWith('1');
      case 'string':
        // Decode string from hex
        const bytes = cleanHex.match(/.{2}/g) || [];
        return bytes.map(byte => String.fromCharCode(parseInt(byte, 16))).join('');
      default:
        return cleanHex;
    }
  }
  
  base58ToHex(base58Address) {
    // Simplified conversion - use proper library in production
    // This is a placeholder implementation
    return base58Address; // Would need actual conversion
  }
  
  hexToBase58(hexAddress) {
    // Simplified conversion - use proper library in production
    return hexAddress; // Would need actual conversion
  }
}

// TRC20 Token interaction class
class TRC20Token extends TronSmartContract {
  async getBalance(walletAddress) {
    try {
      const encodedAddress = this.encodeAddress(walletAddress);
      const result = await this.call('balanceOf(address)', encodedAddress, walletAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        const balance = this.decodeResult(result.constant_result[0], 'uint256');
        return balance;
      }
      
      throw new Error('Failed to get balance');
    } catch (error) {
      console.error('Error getting balance:', error);
      throw error;
    }
  }
  
  async getDecimals() {
    try {
      const result = await this.call('decimals()', '', this.contractAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return parseInt(this.decodeResult(result.constant_result[0], 'uint256'));
      }
      
      return 6; // Default for most TRC20 tokens
    } catch (error) {
      console.error('Error getting decimals:', error);
      return 6;
    }
  }
  
  async getSymbol() {
    try {
      const result = await this.call('symbol()', '', this.contractAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.decodeResult(result.constant_result[0], 'string');
      }
      
      throw new Error('Failed to get symbol');
    } catch (error) {
      console.error('Error getting symbol:', error);
      throw error;
    }
  }
  
  async getName() {
    try {
      const result = await this.call('name()', '', this.contractAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.decodeResult(result.constant_result[0], 'string');
      }
      
      throw new Error('Failed to get name');
    } catch (error) {
      console.error('Error getting name:', error);
      throw error;
    }
  }
  
  async getTotalSupply() {
    try {
      const result = await this.call('totalSupply()', '', this.contractAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.decodeResult(result.constant_result[0], 'uint256');
      }
      
      throw new Error('Failed to get total supply');
    } catch (error) {
      console.error('Error getting total supply:', error);
      throw error;
    }
  }
  
  // Create transfer transaction (returns unsigned transaction)
  async createTransfer(fromAddress, toAddress, amount) {
    try {
      const encodedTo = this.encodeAddress(toAddress);
      const encodedAmount = this.encodeUint256(amount);
      const parameters = encodedTo + encodedAmount;
      
      const result = await this.call(
        'transfer(address,uint256)', 
        parameters, 
        fromAddress
      );
      
      if (result.result?.result) {
        return result.transaction;
      }
      
      throw new Error(`Transfer creation failed: ${result.result?.message || 'Unknown error'}`);
    } catch (error) {
      console.error('Error creating transfer:', error);
      throw error;
    }
  }
  
  async getAllowance(ownerAddress, spenderAddress) {
    try {
      const encodedOwner = this.encodeAddress(ownerAddress);
      const encodedSpender = this.encodeAddress(spenderAddress);
      const parameters = encodedOwner + encodedSpender;
      
      const result = await this.call(
        'allowance(address,address)', 
        parameters, 
        ownerAddress
      );
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.decodeResult(result.constant_result[0], 'uint256');
      }
      
      return '0';
    } catch (error) {
      console.error('Error getting allowance:', error);
      throw error;
    }
  }
}

// DeFi protocol interaction example
class TronDeFiProtocol extends TronSmartContract {
  async getPoolInfo(poolId) {
    try {
      const encodedPoolId = this.encodeUint256(poolId);
      const result = await this.call('poolInfo(uint256)', encodedPoolId, this.contractAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        // Decode pool info struct - simplified example
        const poolData = result.constant_result[0];
        return {
          lpToken: this.decodeResult(poolData.slice(0, 64), 'address'),
          allocPoint: this.decodeResult(poolData.slice(64, 128), 'uint256'),
          lastRewardBlock: this.decodeResult(poolData.slice(128, 192), 'uint256'),
          accTokenPerShare: this.decodeResult(poolData.slice(192, 256), 'uint256')
        };
      }
      
      throw new Error('Failed to get pool info');
    } catch (error) {
      console.error('Error getting pool info:', error);
      throw error;
    }
  }
  
  async getUserInfo(poolId, userAddress) {
    try {
      const encodedPoolId = this.encodeUint256(poolId);
      const encodedUser = this.encodeAddress(userAddress);
      const parameters = encodedPoolId + encodedUser;
      
      const result = await this.call('userInfo(uint256,address)', parameters, userAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        const userData = result.constant_result[0];
        return {
          amount: this.decodeResult(userData.slice(0, 64), 'uint256'),
          rewardDebt: this.decodeResult(userData.slice(64, 128), 'uint256')
        };
      }
      
      throw new Error('Failed to get user info');
    } catch (error) {
      console.error('Error getting user info:', error);
      throw error;
    }
  }
}

// Usage examples
(async () => {
  try {
    // USDT TRC20 token interaction
    const USDT_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
    const usdt = new TRC20Token('YOUR_API_KEY', USDT_CONTRACT);
    
    const walletAddress = 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN';
    
    // Get token information
    const [balance, decimals, symbol, name] = await Promise.all([
      usdt.getBalance(walletAddress),
      usdt.getDecimals(),
      usdt.getSymbol(),
      usdt.getName()
    ]);
    
    console.log(`Token: ${name} (${symbol})`);
    console.log(`Balance: ${balance / Math.pow(10, decimals)} ${symbol}`);
    
    // Create transfer transaction
    const transferTx = await usdt.createTransfer(
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
      'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN',
      1000000 // 1 USDT (6 decimals)
    );
    console.log('Transfer transaction created:', transferTx.txID);
    
    // Check allowance
    const allowance = await usdt.getAllowance(
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh',
      'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
    );
    console.log('Allowance:', allowance);
    
  } catch (error) {
    console.error('Error:', error);
  }
})();
```

```python
import requests
import json
from typing import Dict, List, Optional, Union

class TronSmartContract:
    def __init__(self, api_key: str, contract_address: str):
        self.api_key = api_key
        self.contract_address = contract_address
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {
            'Content-Type': 'application/json'
        }
    
    def call(self, function_selector: str, parameters: str = '', 
             owner_address: str = None, call_value: int = 0) -> Dict:
        """Call smart contract function"""
        url = f"{self.base_url}/wallet/triggersmartcontract"
        
        payload = {
            "contract_address": self.contract_address,
            "function_selector": function_selector,
            "parameter": parameters,
            "owner_address": owner_address or self.contract_address,
            "call_value": call_value,
            "visible": True
        }
        
        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        
        return response.json()
    
    def encode_address(self, address: str) -> str:
        """Encode address for contract parameters"""
        # Simplified encoding - use proper library in production
        # Remove 'T' prefix and convert to hex representation
        return address.replace('T', '').lower().zfill(64)
    
    def encode_uint256(self, value: Union[int, str]) -> str:
        """Encode uint256 for contract parameters"""
        return format(int(value), '064x')
    
    def decode_result(self, hex_result: str, result_type: str = 'uint256'):
        """Decode contract call result"""
        if not hex_result or hex_result == '0x':
            return None
        
        # Remove 0x prefix if present
        clean_hex = hex_result.replace('0x', '')
        
        if result_type == 'uint256':
            return str(int(clean_hex, 16))
        elif result_type == 'bool':
            return clean_hex.endswith('1')
        elif result_type == 'string':
            # Simplified string decoding
            try:
                bytes_data = bytes.fromhex(clean_hex)
                return bytes_data.decode('utf-8').rstrip('\x00')
            except:
                return clean_hex
        else:
            return clean_hex

class TRC20Token(TronSmartContract):
    """TRC20 token interaction class"""
    
    def get_balance(self, wallet_address: str) -> str:
        """Get token balance for address"""
        try:
            encoded_address = self.encode_address(wallet_address)
            result = self.call('balanceOf(address)', encoded_address, wallet_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                balance = self.decode_result(result['constant_result'][0], 'uint256')
                return balance
            
            raise Exception('Failed to get balance')
        except Exception as e:
            print(f"Error getting balance: {e}")
            raise
    
    def get_decimals(self) -> int:
        """Get token decimals"""
        try:
            result = self.call('decimals()', '', self.contract_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                return int(self.decode_result(result['constant_result'][0], 'uint256'))
            
            return 6  # Default for most TRC20 tokens
        except Exception as e:
            print(f"Error getting decimals: {e}")
            return 6
    
    def get_symbol(self) -> str:
        """Get token symbol"""
        try:
            result = self.call('symbol()', '', self.contract_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                return self.decode_result(result['constant_result'][0], 'string')
            
            raise Exception('Failed to get symbol')
        except Exception as e:
            print(f"Error getting symbol: {e}")
            raise
    
    def get_name(self) -> str:
        """Get token name"""
        try:
            result = self.call('name()', '', self.contract_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                return self.decode_result(result['constant_result'][0], 'string')
            
            raise Exception('Failed to get name')
        except Exception as e:
            print(f"Error getting name: {e}")
            raise
    
    def get_total_supply(self) -> str:
        """Get total token supply"""
        try:
            result = self.call('totalSupply()', '', self.contract_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                return self.decode_result(result['constant_result'][0], 'uint256')
            
            raise Exception('Failed to get total supply')
        except Exception as e:
            print(f"Error getting total supply: {e}")
            raise
    
    def create_transfer(self, from_address: str, to_address: str, amount: int) -> Dict:
        """Create transfer transaction"""
        try:
            encoded_to = self.encode_address(to_address)
            encoded_amount = self.encode_uint256(amount)
            parameters = encoded_to + encoded_amount
            
            result = self.call('transfer(address,uint256)', parameters, from_address)
            
            if result.get('result', {}).get('result'):
                return result['transaction']
            
            raise Exception(f"Transfer creation failed: {result.get('result', {}).get('message', 'Unknown error')}")
        except Exception as e:
            print(f"Error creating transfer: {e}")
            raise
    
    def get_allowance(self, owner_address: str, spender_address: str) -> str:
        """Get allowance amount"""
        try:
            encoded_owner = self.encode_address(owner_address)
            encoded_spender = self.encode_address(spender_address)
            parameters = encoded_owner + encoded_spender
            
            result = self.call('allowance(address,address)', parameters, owner_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                return self.decode_result(result['constant_result'][0], 'uint256')
            
            return '0'
        except Exception as e:
            print(f"Error getting allowance: {e}")
            raise
    
    def get_formatted_balance(self, wallet_address: str) -> Dict:
        """Get formatted balance with token info"""
        try:
            balance_raw = self.get_balance(wallet_address)
            decimals = self.get_decimals()
            symbol = self.get_symbol()
            
            balance_formatted = float(balance_raw) / (10 ** decimals)
            
            return {
                'raw': balance_raw,
                'formatted': balance_formatted,
                'decimals': decimals,
                'symbol': symbol
            }
        except Exception as e:
            print(f"Error getting formatted balance: {e}")
            raise

class TronDeFiProtocol(TronSmartContract):
    """DeFi protocol interaction example"""
    
    def get_pool_info(self, pool_id: int) -> Dict:
        """Get liquidity pool information"""
        try:
            encoded_pool_id = self.encode_uint256(pool_id)
            result = self.call('poolInfo(uint256)', encoded_pool_id, self.contract_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                pool_data = result['constant_result'][0]
                
                # Decode pool info struct (simplified)
                return {
                    'lp_token': pool_data[0:64],  # Would need proper address decoding
                    'alloc_point': self.decode_result(pool_data[64:128], 'uint256'),
                    'last_reward_block': self.decode_result(pool_data[128:192], 'uint256'),
                    'acc_token_per_share': self.decode_result(pool_data[192:256], 'uint256')
                }
            
            raise Exception('Failed to get pool info')
        except Exception as e:
            print(f"Error getting pool info: {e}")
            raise
    
    def get_user_info(self, pool_id: int, user_address: str) -> Dict:
        """Get user staking information"""
        try:
            encoded_pool_id = self.encode_uint256(pool_id)
            encoded_user = self.encode_address(user_address)
            parameters = encoded_pool_id + encoded_user
            
            result = self.call('userInfo(uint256,address)', parameters, user_address)
            
            if result.get('result', {}).get('result') and result.get('constant_result'):
                user_data = result['constant_result'][0]
                
                return {
                    'amount': self.decode_result(user_data[0:64], 'uint256'),
                    'reward_debt': self.decode_result(user_data[64:128], 'uint256')
                }
            
            raise Exception('Failed to get user info')
        except Exception as e:
            print(f"Error getting user info: {e}")
            raise

class TronContractManager:
    """Manage multiple contract interactions"""
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.contracts = {}
        
        # Popular TRON contracts
        self.popular_contracts = {
            'USDT': 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
            'USDC': 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8',
            'WTRX': 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR',
            'JST': 'TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9'
        }
    
    def get_token(self, symbol_or_address: str) -> TRC20Token:
        """Get TRC20 token instance"""
        address = self.popular_contracts.get(symbol_or_address, symbol_or_address)
        
        if address not in self.contracts:
            self.contracts[address] = TRC20Token(self.api_key, address)
        
        return self.contracts[address]
    
    def get_portfolio_balances(self, wallet_address: str, tokens: List[str] = None) -> Dict:
        """Get balances for multiple tokens"""
        if tokens is None:
            tokens = list(self.popular_contracts.keys())
        
        portfolio = {}
        
        for token_symbol in tokens:
            try:
                token = self.get_token(token_symbol)
                balance_info = token.get_formatted_balance(wallet_address)
                portfolio[token_symbol] = balance_info
            except Exception as e:
                portfolio[token_symbol] = {'error': str(e)}
        
        return portfolio
    
    def batch_contract_calls(self, calls: List[Dict]) -> List[Dict]:
        """Execute multiple contract calls"""
        results = []
        
        for call in calls:
            try:
                contract = TronSmartContract(self.api_key, call['contract_address'])
                result = contract.call(
                    call['function_selector'],
                    call.get('parameters', ''),
                    call.get('owner_address', call['contract_address'])
                )
                results.append({
                    'success': True,
                    'call': call,
                    'result': result
                })
            except Exception as e:
                results.append({
                    'success': False,
                    'call': call,
                    'error': str(e)
                })
        
        return results

# Usage examples
if __name__ == "__main__":
    manager = TronContractManager('YOUR_API_KEY')
    
    try:
        # Get USDT token info
        usdt = manager.get_token('USDT')
        wallet_address = 'TRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN'
        
        # Get token information
        name = usdt.get_name()
        symbol = usdt.get_symbol()
        decimals = usdt.get_decimals()
        balance_info = usdt.get_formatted_balance(wallet_address)
        
        print(f"Token: {name} ({symbol})")
        print(f"Decimals: {decimals}")
        print(f"Balance: {balance_info['formatted']} {balance_info['symbol']}")
        
        # Get portfolio balances
        portfolio = manager.get_portfolio_balances(wallet_address, ['USDT', 'USDC', 'JST'])
        
        print("\nPortfolio:")
        for token, info in portfolio.items():
            if 'error' in info:
                print(f"{token}: Error - {info['error']}")
            else:
                print(f"{token}: {info['formatted']} {info['symbol']}")
        
        # Batch contract calls example
        batch_calls = [
            {
                'contract_address': 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
                'function_selector': 'name()',
                'owner_address': wallet_address
            },
            {
                'contract_address': 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
                'function_selector': 'symbol()',
                'owner_address': wallet_address
            }
        ]
        
        batch_results = manager.batch_contract_calls(batch_calls)
        print(f"\nBatch calls completed: {len([r for r in batch_results if r['success']])}/{len(batch_results)} successful")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Successful View Function Call (balanceOf)

```json
{
  "result": {
    "result": true
  },
  "energy_used": 345,
  "constant_result": [
    "0000000000000000000000000000000000000000000000000000000005f5e100"
  ],
  "transaction": {
    "ret": [{}],
    "visible": true,
    "txID": "70c8e5b0b4e13a7e5a1b0e8d7c6b5a4a39291807f6e5d4c3b2a19080f0e0d0c0b0",
    "raw_data": {
      "contract": [
        {
          "parameter": {
            "value": {
              "data": "70a082310000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e863",
              "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
              "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
            },
            "type_url": "type.googleapis.com/protocol.TriggerSmartContract"
          },
          "type": "TriggerSmartContract"
        }
      ],
      "ref_block_bytes": "4a7b",
      "ref_block_hash": "e15e44aa73bd9e15",
      "expiration": 1734567890000,
      "timestamp": 1734567830000
    }
  }
}
```

### Failed Contract Call

```json
{
  "result": {
    "result": false,
    "code": "REVERT",
    "message": "REVERT opcode executed"
  },
  "energy_used": 250
}
```

### State-Changing Function Call (Transfer)

```json
{
  "result": {
    "result": true
  },
  "energy_used": 13326,
  "energy_penalty": 0,
  "transaction": {
    "visible": true,
    "txID": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890",
    "raw_data": {
      "contract": [
        {
          "parameter": {
            "value": {
              "data": "a9059cbb0000000000000000000000004142b5e01c8c59a25d78acdbec2bfc7e89e5e86300000000000000000000000000000000000000000000000000000000000f4240",
              "owner_address": "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh",
              "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
            },
            "type_url": "type.googleapis.com/protocol.TriggerSmartContract"
          },
          "type": "TriggerSmartContract"
        }
      ],
      "ref_block_bytes": "4a7b",
      "ref_block_hash": "e15e44aa73bd9e15",
      "expiration": 1734567890000,
      "timestamp": 1734567830000
    }
  }
}
```

## Common Use Cases

### 1. Portfolio Tracker

```javascript
class TronPortfolioTracker {
  constructor(apiKey) {
    this.manager = new TronContractManager(apiKey);
    this.supportedTokens = {
      'USDT': 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
      'USDC': 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8',
      'JST': 'TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9',
      'WTRX': 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR',
      'TUSD': 'TUpMhErZL2fhh4sVNULAbNKLokS4GjC1F4'
    };
  }
  
  async getPortfolio(walletAddress, includeMetadata = true) {
    const portfolio = {
      address: walletAddress,
      tokens: {},
      totalValueUSD: 0,
      lastUpdated: new Date().toISOString()
    };
    
    for (const [symbol, contractAddress] of Object.entries(this.supportedTokens)) {
      try {
        const token = this.manager.getToken(contractAddress);
        const balanceInfo = await token.getFormattedBalance(walletAddress);
        
        portfolio.tokens[symbol] = {
          ...balanceInfo,
          contractAddress,
          valueUSD: await this.getTokenValueUSD(symbol, balanceInfo.formatted)
        };
        
        if (includeMetadata) {
          const [name, totalSupply] = await Promise.all([
            token.getName(),
            token.getTotalSupply()
          ]);
          
          portfolio.tokens[symbol].name = name;
          portfolio.tokens[symbol].totalSupply = totalSupply;
        }
        
        portfolio.totalValueUSD += portfolio.tokens[symbol].valueUSD;
        
      } catch (error) {
        portfolio.tokens[symbol] = {
          error: error.message,
          contractAddress
        };
      }
    }
    
    return portfolio;
  }
  
  async getTokenValueUSD(symbol, amount) {
    // Simplified - would integrate with price API
    const prices = {
      'USDT': 1.00,
      'USDC': 1.00,
      'TUSD': 1.00,
      'JST': 0.025,
      'WTRX': 0.065
    };
    
    return (prices[symbol] || 0) * amount;
  }
}
```

### 2. DeFi Yield Farming Interface

```javascript
class TronYieldFarming {
  constructor(apiKey, farmContractAddress) {
    this.contract = new TronSmartContract(apiKey, farmContractAddress);
    this.tokenManager = new TronContractManager(apiKey);
  }
  
  async getFarmInfo() {
    try {
      const [poolLength, rewardPerBlock, startBlock] = await Promise.all([
        this.contract.call('poolLength()'),
        this.contract.call('rewardPerBlock()'),
        this.contract.call('startBlock()')
      ]);
      
      return {
        totalPools: this.contract.decodeResult(poolLength.constant_result[0], 'uint256'),
        rewardPerBlock: this.contract.decodeResult(rewardPerBlock.constant_result[0], 'uint256'),
        startBlock: this.contract.decodeResult(startBlock.constant_result[0], 'uint256')
      };
    } catch (error) {
      console.error('Error getting farm info:', error);
      throw error;
    }
  }
  
  async getPoolInfo(poolId) {
    try {
      const encodedPoolId = this.contract.encodeUint256(poolId);
      const result = await this.contract.call('poolInfo(uint256)', encodedPoolId);
      
      if (result.result?.result && result.constant_result?.[0]) {
        const poolData = result.constant_result[0];
        return {
          lpToken: poolData.slice(24, 64), // Extract address
          allocPoint: this.contract.decodeResult(poolData.slice(64, 128), 'uint256'),
          lastRewardBlock: this.contract.decodeResult(poolData.slice(128, 192), 'uint256'),
          accRewardPerShare: this.contract.decodeResult(poolData.slice(192, 256), 'uint256')
        };
      }
      
      throw new Error('Failed to get pool info');
    } catch (error) {
      console.error('Error getting pool info:', error);
      throw error;
    }
  }
  
  async getUserStakeInfo(poolId, userAddress) {
    try {
      const encodedPoolId = this.contract.encodeUint256(poolId);
      const encodedUser = this.contract.encodeAddress(userAddress);
      const parameters = encodedPoolId + encodedUser;
      
      const result = await this.contract.call('userInfo(uint256,address)', parameters, userAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        const userData = result.constant_result[0];
        return {
          amount: this.contract.decodeResult(userData.slice(0, 64), 'uint256'),
          rewardDebt: this.contract.decodeResult(userData.slice(64, 128), 'uint256')
        };
      }
      
      return { amount: '0', rewardDebt: '0' };
    } catch (error) {
      console.error('Error getting user stake info:', error);
      throw error;
    }
  }
  
  async getPendingRewards(poolId, userAddress) {
    try {
      const encodedPoolId = this.contract.encodeUint256(poolId);
      const encodedUser = this.contract.encodeAddress(userAddress);
      const parameters = encodedPoolId + encodedUser;
      
      const result = await this.contract.call('pendingReward(uint256,address)', parameters, userAddress);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.contract.decodeResult(result.constant_result[0], 'uint256');
      }
      
      return '0';
    } catch (error) {
      console.error('Error getting pending rewards:', error);
      return '0';
    }
  }
  
  async createStakeTransaction(poolId, amount, userAddress) {
    try {
      const encodedPoolId = this.contract.encodeUint256(poolId);
      const encodedAmount = this.contract.encodeUint256(amount);
      const parameters = encodedPoolId + encodedAmount;
      
      const result = await this.contract.call('deposit(uint256,uint256)', parameters, userAddress);
      
      if (result.result?.result) {
        return result.transaction;
      }
      
      throw new Error(`Stake transaction creation failed: ${result.result?.message || 'Unknown error'}`);
    } catch (error) {
      console.error('Error creating stake transaction:', error);
      throw error;
    }
  }
}
```

### 3. NFT Marketplace Integration

```javascript
class TronNFTMarketplace {
  constructor(apiKey, nftContractAddress) {
    this.contract = new TronSmartContract(apiKey, nftContractAddress);
  }
  
  async getNFTInfo(tokenId) {
    try {
      const encodedTokenId = this.contract.encodeUint256(tokenId);
      
      const [owner, tokenURI, approved] = await Promise.all([
        this.contract.call('ownerOf(uint256)', encodedTokenId),
        this.contract.call('tokenURI(uint256)', encodedTokenId),
        this.contract.call('getApproved(uint256)', encodedTokenId)
      ]);
      
      return {
        tokenId: tokenId,
        owner: this.contract.decodeResult(owner.constant_result[0], 'address'),
        tokenURI: this.contract.decodeResult(tokenURI.constant_result[0], 'string'),
        approved: this.contract.decodeResult(approved.constant_result[0], 'address')
      };
    } catch (error) {
      console.error('Error getting NFT info:', error);
      throw error;
    }
  }
  
  async getTokenBalance(owner) {
    try {
      const encodedOwner = this.contract.encodeAddress(owner);
      const result = await this.contract.call('balanceOf(address)', encodedOwner, owner);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.contract.decodeResult(result.constant_result[0], 'uint256');
      }
      
      return '0';
    } catch (error) {
      console.error('Error getting token balance:', error);
      return '0';
    }
  }
  
  async createTransferTransaction(from, to, tokenId) {
    try {
      const encodedFrom = this.contract.encodeAddress(from);
      const encodedTo = this.contract.encodeAddress(to);
      const encodedTokenId = this.contract.encodeUint256(tokenId);
      const parameters = encodedFrom + encodedTo + encodedTokenId;
      
      const result = await this.contract.call(
        'transferFrom(address,address,uint256)', 
        parameters, 
        from
      );
      
      if (result.result?.result) {
        return result.transaction;
      }
      
      throw new Error(`Transfer creation failed: ${result.result?.message || 'Unknown error'}`);
    } catch (error) {
      console.error('Error creating transfer transaction:', error);
      throw error;
    }
  }
}
```

### 4. Automated Trading Bot

```javascript
class TronTradingBot {
  constructor(apiKey, dexContractAddress) {
    this.dex = new TronSmartContract(apiKey, dexContractAddress);
    this.tokenManager = new TronContractManager(apiKey);
    this.strategies = new Map();
  }
  
  async getTokenPrice(tokenAddress, baseTokenAddress = 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR') {
    try {
      const encodedToken = this.dex.encodeAddress(tokenAddress);
      const encodedBase = this.dex.encodeAddress(baseTokenAddress);
      const parameters = encodedToken + encodedBase;
      
      const result = await this.dex.call('getPrice(address,address)', parameters);
      
      if (result.result?.result && result.constant_result?.[0]) {
        return this.dex.decodeResult(result.constant_result[0], 'uint256');
      }
      
      return '0';
    } catch (error) {
      console.error('Error getting token price:', error);
      return '0';
    }
  }
  
  async createSwapTransaction(tokenA, tokenB, amountIn, minAmountOut, userAddress) {
    try {
      const encodedTokenA = this.dex.encodeAddress(tokenA);
      const encodedTokenB = this.dex.encodeAddress(tokenB);
      const encodedAmountIn = this.dex.encodeUint256(amountIn);
      const encodedMinOut = this.dex.encodeUint256(minAmountOut);
      const encodedUser = this.dex.encodeAddress(userAddress);
      
      const parameters = encodedTokenA + encodedTokenB + encodedAmountIn + encodedMinOut + encodedUser;
      
      const result = await this.dex.call(
        'swapExactTokensForTokens(address,address,uint256,uint256,address)', 
        parameters, 
        userAddress
      );
      
      if (result.result?.result) {
        return result.transaction;
      }
      
      throw new Error(`Swap creation failed: ${result.result?.message || 'Unknown error'}`);
    } catch (error) {
      console.error('Error creating swap transaction:', error);
      throw error;
    }
  }
  
  addStrategy(name, strategy) {
    this.strategies.set(name, strategy);
  }
  
  async executeStrategy(strategyName, params) {
    const strategy = this.strategies.get(strategyName);
    if (!strategy) {
      throw new Error(`Strategy ${strategyName} not found`);
    }
    
    return await strategy.execute(this, params);
  }
}
```

## Performance Tips

1. **Batch Contract Calls** - Group multiple read operations together
2. **Cache Results** - Cache contract state that doesn't change frequently
3. **Optimize Parameters** - Pre-encode parameters to reduce processing time
4. **Energy Management** - Monitor energy usage and optimize contract interactions

```javascript
// Optimized contract interaction with caching
class OptimizedContractClient {
  constructor(apiKey, contractAddress) {
    this.contract = new TronSmartContract(apiKey, contractAddress);
    this.cache = new Map();
    this.cacheTimeout = 60000; // 1 minute
  }
  
  async callWithCache(functionSelector, parameters, cacheKey, ttl = this.cacheTimeout) {
    const cached = this.cache.get(cacheKey);
    if (cached && Date.now() - cached.timestamp < ttl) {
      return cached.result;
    }
    
    const result = await this.contract.call(functionSelector, parameters);
    
    this.cache.set(cacheKey, {
      result,
      timestamp: Date.now()
    });
    
    return result;
  }
  
  clearCache() {
    this.cache.clear();
  }
}
```

***

*Need help? Contact our [support team](mailto:support@dwellir.com) or check the [TRON documentation](https://www.dwellir.com/docs/tron).*

---

## wallet/undelegateresource - Reclaim Delegated R...

# wallet/undelegateresource - Reclaim Delegated R...

Reclaim previously delegated bandwidth or energy resources from another account.

## Endpoint

```
POST /wallet/undelegateresource
```

## Request Parameters

- `owner_address` (`string, required`): Required parameter: Account address that delegated resources (base58)
- `receiver_address` (`string, required`): Required parameter: Account that received delegated resources (base58)
- `balance` (`number, required`): Required parameter: Amount to undelegate in SUN (1 TRX = 1,000,000 SUN)
- `resource` (`string, required`): Required parameter: Resource type: "BANDWIDTH" or "ENERGY"
- `permission_id` (`number, required`): Optional parameter: Permission ID for multi-signature (default: 0)
- `visible` (`boolean, required`): Optional parameter: Return base58 addresses (default: false returns hex)

## Request Example

```bash
# Basic undelegation of energy
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TOwnerAddress...",
        "receiver_address": "TReceiverAddress...",
        "balance": 1000000000,
        "resource": "ENERGY",
        "visible": true
      }'

    # Undelegate bandwidth
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TOwnerAddress...",
        "receiver_address": "TReceiverAddress...",
        "balance": 500000000,
        "resource": "BANDWIDTH",
        "visible": true
      }'

    # Check delegation index (to find all delegations)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresourceaccountindex \
      -H "Content-Type: application/json" \
      -d '{
        "value": "TOwnerAddress...",
        "visible": true
      }'

    # Get specific delegation details
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresource \
      -H "Content-Type: application/json" \
      -d '{
        "fromAddress": "TOwnerAddress...",
        "toAddress": "TReceiverAddress...",
        "visible": true
      }'

    # Check receiver's resource usage (to analyze efficiency)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountresource \
      -H "Content-Type: application/json" \
      -d '{
        "address": "TReceiverAddress...",
        "visible": true
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `txID` - Transaction hash `raw_data` - Transaction raw data `contract` - Undelegation contract details `expiration` - Transaction expiration timestamp `timestamp` - Transaction creation timestamp `visible` - Address format indicator

## Successful Response

```json
{
  "visible": true,
  "txID": "a9f4d3c2b1e8a7d6c5e4f3b2a1d9c8e7f6b5a4d3c2e1f9a8b7c6d5e4f3a2b1c8",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "owner_address": "TOwnerAddress...",
            "receiver_address": "TReceiverAddress...",
            "balance": 1000000000,
            "resource": "ENERGY"
          },
          "type_url": "type.googleapis.com/protocol.UnDelegateResourceContract"
        },
        "type": "UnDelegateResourceContract"
      }
    ],
    "ref_block_bytes": "7c6d",
    "ref_block_hash": "5e4f9b8a7c6d5e3f",
    "expiration": 1702456849000,
    "timestamp": 1702456789000
  }
}
```

## Important Notes

### Undelegation Rules

1. **Lock Period Check**: Cannot undelegate if resources are locked
2. **Immediate Effect**: Resources return to owner immediately after confirmation
3. **Partial Undelegation**: Can undelegate portions of delegated amount
4. **Resource Availability**: Reclaimed resources are immediately available to owner
5. **No Waiting Period**: Unlike unstaking, undelegation has no waiting period

### Key Differences from Unstaking

- **Undelegation**: Returns delegated resources to owner (immediate)
- **Unstaking**: Converts staked TRX back to liquid (14-day wait)

## Implementation Examples

cURL
JavaScript
Python

```bash
# Basic undelegation of energy
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TOwnerAddress...",
    "receiver_address": "TReceiverAddress...",
    "balance": 1000000000,
    "resource": "ENERGY",
    "visible": true
  }'

# Undelegate bandwidth
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TOwnerAddress...",
    "receiver_address": "TReceiverAddress...",
    "balance": 500000000,
    "resource": "BANDWIDTH",
    "visible": true
  }'

# Check delegation index (to find all delegations)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresourceaccountindex \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TOwnerAddress...",
    "visible": true
  }'

# Get specific delegation details
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresource \
  -H "Content-Type: application/json" \
  -d '{
    "fromAddress": "TOwnerAddress...",
    "toAddress": "TReceiverAddress...",
    "visible": true
  }'

# Check receiver's resource usage (to analyze efficiency)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountresource \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TReceiverAddress...",
    "visible": true
  }'
```

```javascript
class TronUndelegationManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }

  // Create undelegation transaction
  async undelegateResources(ownerAddress, receiverAddress, amountTRX, resourceType) {
    const response = await fetch(`${this.baseUrl}/wallet/undelegateresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        owner_address: ownerAddress,
        receiver_address: receiverAddress,
        balance: amountTRX * 1000000, // Convert TRX to SUN
        resource: resourceType,
        visible: true
      })
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Undelegation failed: ${error.message || response.statusText}`);
    }

    return response.json();
  }

  // Get all active delegations from owner
  async getActiveDelegations(ownerAddress) {
    const response = await fetch(`${this.baseUrl}/wallet/getdelegatedresourceaccountindex`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        value: ownerAddress,
        visible: true
      })
    });

    const index = await response.json();
    const delegations = [];

    if (index.toAccounts) {
      for (const receiverAddress of index.toAccounts) {
        const detail = await this.getDelegationDetail(ownerAddress, receiverAddress);
        delegations.push({
          receiver: receiverAddress,
          ...this.parseDelegationDetail(detail)
        });
      }
    }

    return delegations;
  }

  // Get delegation detail between two accounts
  async getDelegationDetail(fromAddress, toAddress) {
    const response = await fetch(`${this.baseUrl}/wallet/getdelegatedresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        fromAddress: fromAddress,
        toAddress: toAddress,
        visible: true
      })
    });

    return response.json();
  }

  // Parse delegation details
  parseDelegationDetail(detail) {
    const delegatedResource = detail.delegatedResource || [];
    let energyDelegated = 0;
    let bandwidthDelegated = 0;
    let energyExpireTime = null;
    let bandwidthExpireTime = null;

    for (const resource of delegatedResource) {
      if (resource.frozen_balance_for_energy) {
        energyDelegated = resource.frozen_balance_for_energy / 1000000; // Convert to TRX
        energyExpireTime = resource.expire_time_for_energy 
          ? new Date(resource.expire_time_for_energy) 
          : null;
      }
      if (resource.frozen_balance_for_bandwidth) {
        bandwidthDelegated = resource.frozen_balance_for_bandwidth / 1000000; // Convert to TRX
        bandwidthExpireTime = resource.expire_time_for_bandwidth 
          ? new Date(resource.expire_time_for_bandwidth) 
          : null;
      }
    }

    return {
      energy: {
        amount: energyDelegated,
        locked: energyExpireTime && energyExpireTime > new Date(),
        expireTime: energyExpireTime
      },
      bandwidth: {
        amount: bandwidthDelegated,
        locked: bandwidthExpireTime && bandwidthExpireTime > new Date(),
        expireTime: bandwidthExpireTime
      }
    };
  }

  // Check if undelegation is possible
  async canUndelegate(ownerAddress, receiverAddress, resourceType) {
    const detail = await this.getDelegationDetail(ownerAddress, receiverAddress);
    const parsed = this.parseDelegationDetail(detail);
    
    const resource = resourceType.toLowerCase();
    const delegation = parsed[resource];
    
    if (!delegation || delegation.amount === 0) {
      return {
        canUndelegate: false,
        reason: 'No resources delegated',
        amount: 0
      };
    }
    
    if (delegation.locked) {
      const remainingTime = delegation.expireTime - new Date();
      const days = Math.ceil(remainingTime / (1000 * 60 * 60 * 24));
      
      return {
        canUndelegate: false,
        reason: `Resources locked for ${days} more days`,
        amount: delegation.amount,
        unlockTime: delegation.expireTime
      };
    }
    
    return {
      canUndelegate: true,
      amount: delegation.amount,
      reason: 'Ready to undelegate'
    };
  }

  // Batch undelegate from multiple receivers
  async batchUndelegate(ownerAddress, undelegations) {
    const results = [];
    
    for (const undelegation of undelegations) {
      try {
        // Check if can undelegate first
        const check = await this.canUndelegate(
          ownerAddress,
          undelegation.receiver,
          undelegation.resource
        );
        
        if (!check.canUndelegate) {
          results.push({
            success: false,
            receiver: undelegation.receiver,
            resource: undelegation.resource,
            reason: check.reason
          });
          continue;
        }
        
        // Proceed with undelegation
        const tx = await this.undelegateResources(
          ownerAddress,
          undelegation.receiver,
          undelegation.amount || check.amount,
          undelegation.resource
        );
        
        results.push({
          success: true,
          receiver: undelegation.receiver,
          resource: undelegation.resource,
          amount: undelegation.amount || check.amount,
          txID: tx.txID,
          transaction: tx
        });
        
      } catch (error) {
        results.push({
          success: false,
          receiver: undelegation.receiver,
          resource: undelegation.resource,
          error: error.message
        });
      }
    }
    
    return results;
  }

  // Reclaim all unlocked delegations
  async reclaimAllUnlocked(ownerAddress) {
    const delegations = await this.getActiveDelegations(ownerAddress);
    const toReclaim = [];
    
    for (const delegation of delegations) {
      // Check energy delegation
      if (delegation.energy.amount > 0 && !delegation.energy.locked) {
        toReclaim.push({
          receiver: delegation.receiver,
          resource: 'ENERGY',
          amount: delegation.energy.amount
        });
      }
      
      // Check bandwidth delegation
      if (delegation.bandwidth.amount > 0 && !delegation.bandwidth.locked) {
        toReclaim.push({
          receiver: delegation.receiver,
          resource: 'BANDWIDTH',
          amount: delegation.bandwidth.amount
        });
      }
    }
    
    if (toReclaim.length === 0) {
      return {
        message: 'No unlocked delegations to reclaim',
        transactions: []
      };
    }
    
    const results = await this.batchUndelegate(ownerAddress, toReclaim);
    
    return {
      message: `Reclaiming ${toReclaim.length} delegations`,
      transactions: results
    };
  }
}

// Resource optimization strategies
class ResourceOptimizer {
  constructor(manager) {
    this.manager = manager;
  }

  // Analyze delegation efficiency
  async analyzeDelegationEfficiency(ownerAddress) {
    const delegations = await this.manager.getActiveDelegations(ownerAddress);
    const analysis = [];
    
    for (const delegation of delegations) {
      // Get receiver's current resource usage
      const resourceResponse = await fetch(
        `${this.manager.baseUrl}/wallet/getaccountresource`,
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            address: delegation.receiver,
            visible: true
          })
        }
      );
      
      const resources = await resourceResponse.json();
      
      // Calculate efficiency metrics
      const energyEfficiency = resources.EnergyUsed 
        ? (resources.EnergyUsed / resources.EnergyLimit) * 100 
        : 0;
      
      const bandwidthEfficiency = resources.NetUsed 
        ? (resources.NetUsed / resources.NetLimit) * 100 
        : 0;
      
      analysis.push({
        receiver: delegation.receiver,
        energy: {
          delegated: delegation.energy.amount,
          efficiency: energyEfficiency.toFixed(2) + '%',
          recommendation: energyEfficiency < 50 
            ? 'Consider reducing delegation' 
            : 'Delegation well utilized'
        },
        bandwidth: {
          delegated: delegation.bandwidth.amount,
          efficiency: bandwidthEfficiency.toFixed(2) + '%',
          recommendation: bandwidthEfficiency < 50 
            ? 'Consider reducing delegation' 
            : 'Delegation well utilized'
        }
      });
    }
    
    return analysis;
  }

  // Optimize delegations by reclaiming underutilized resources
  async optimizeDelegations(ownerAddress, utilizationThreshold = 30) {
    const analysis = await this.analyzeDelegationEfficiency(ownerAddress);
    const toReclaim = [];
    
    for (const item of analysis) {
      // Check energy utilization
      const energyUtilization = parseFloat(item.energy.efficiency);
      if (energyUtilization < utilizationThreshold && item.energy.delegated > 0) {
        // Calculate amount to reclaim (keep some buffer)
        const reclaimAmount = item.energy.delegated * (1 - energyUtilization / 100) * 0.8;
        
        toReclaim.push({
          receiver: item.receiver,
          resource: 'ENERGY',
          amount: Math.floor(reclaimAmount),
          reason: `Low utilization: ${item.energy.efficiency}`
        });
      }
      
      // Check bandwidth utilization
      const bandwidthUtilization = parseFloat(item.bandwidth.efficiency);
      if (bandwidthUtilization < utilizationThreshold && item.bandwidth.delegated > 0) {
        // Calculate amount to reclaim
        const reclaimAmount = item.bandwidth.delegated * (1 - bandwidthUtilization / 100) * 0.8;
        
        toReclaim.push({
          receiver: item.receiver,
          resource: 'BANDWIDTH',
          amount: Math.floor(reclaimAmount),
          reason: `Low utilization: ${item.bandwidth.efficiency}`
        });
      }
    }
    
    if (toReclaim.length === 0) {
      return {
        message: 'All delegations are efficiently utilized',
        optimizations: []
      };
    }
    
    const results = await this.manager.batchUndelegate(ownerAddress, toReclaim);
    
    return {
      message: `Optimizing ${toReclaim.length} inefficient delegations`,
      optimizations: results
    };
  }
}

// Example usage
async function manageUndelegation() {
  const manager = new TronUndelegationManager('YOUR_API_KEY');
  const optimizer = new ResourceOptimizer(manager);
  
  try {
    // 1. Simple undelegation
    console.log('=== Simple Undelegation ===');
    const simpleTx = await manager.undelegateResources(
      'TOwnerAddress...',
      'TReceiverAddress...',
      1000, // 1000 TRX
      'ENERGY'
    );
    console.log('Transaction ID:', simpleTx.txID);
    
    // 2. Check if can undelegate
    console.log('\n=== Checking Undelegation Status ===');
    const canUndelegate = await manager.canUndelegate(
      'TOwnerAddress...',
      'TReceiverAddress...',
      'ENERGY'
    );
    console.log('Can undelegate:', canUndelegate);
    
    // 3. Get all active delegations
    console.log('\n=== Active Delegations ===');
    const activeDelegations = await manager.getActiveDelegations('TOwnerAddress...');
    
    for (const delegation of activeDelegations) {
      console.log(`To ${delegation.receiver}:`);
      console.log(`  Energy: ${delegation.energy.amount} TRX (${delegation.energy.locked ? 'LOCKED' : 'UNLOCKED'})`);
      console.log(`  Bandwidth: ${delegation.bandwidth.amount} TRX (${delegation.bandwidth.locked ? 'LOCKED' : 'UNLOCKED'})`);
    }
    
    // 4. Reclaim all unlocked delegations
    console.log('\n=== Reclaiming All Unlocked ===');
    const reclaimResults = await manager.reclaimAllUnlocked('TOwnerAddress...');
    console.log(reclaimResults.message);
    
    for (const tx of reclaimResults.transactions) {
      if (tx.success) {
        console.log(`✓ Reclaimed ${tx.amount} TRX ${tx.resource} from ${tx.receiver}`);
      } else {
        console.log(`✗ Failed to reclaim from ${tx.receiver}: ${tx.reason || tx.error}`);
      }
    }
    
    // 5. Optimize delegations
    console.log('\n=== Delegation Optimization ===');
    const optimization = await optimizer.optimizeDelegations('TOwnerAddress...', 30);
    console.log(optimization.message);
    
    for (const opt of optimization.optimizations) {
      if (opt.success) {
        console.log(`✓ Optimized: Reclaimed ${opt.amount} TRX ${opt.resource} from ${opt.receiver}`);
      } else {
        console.log(`✗ Could not optimize ${opt.receiver}: ${opt.reason}`);
      }
    }
    
  } catch (error) {
    console.error('Undelegation error:', error);
  }
}
```

```python
import requests
import json
from datetime import datetime
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass

@dataclass
class UndelegationRequest:
    receiver: str
    resource: str
    amount: Optional[float] = None  # If None, undelegate all

class TronUndelegationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
    
    def undelegate_resources(
        self,
        owner_address: str,
        receiver_address: str,
        amount_trx: float,
        resource: str
    ) -> Dict:
        """Create an undelegation transaction"""
        
        response = requests.post(
            f"{self.base_url}/wallet/undelegateresource",
            json={
                "owner_address": owner_address,
                "receiver_address": receiver_address,
                "balance": int(amount_trx * 1_000_000),  # Convert to SUN
                "resource": resource,
                "visible": True
            }
        )
        response.raise_for_status()
        return response.json()
    
    def get_delegation_index(self, owner_address: str) -> List[str]:
        """Get list of accounts that have received delegations"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getdelegatedresourceaccountindex",
            json={
                "value": owner_address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        data = response.json()
        return data.get('toAccounts', [])
    
    def get_delegation_detail(
        self,
        from_address: str,
        to_address: str
    ) -> Tuple[Dict, Dict]:
        """Get detailed delegation info between accounts"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getdelegatedresource",
            json={
                "fromAddress": from_address,
                "toAddress": to_address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        data = response.json()
        delegated_resources = data.get('delegatedResource', [])
        
        energy_info = {'amount': 0, 'locked': False, 'expire_time': None}
        bandwidth_info = {'amount': 0, 'locked': False, 'expire_time': None}
        
        for resource in delegated_resources:
            if 'frozen_balance_for_energy' in resource:
                energy_info['amount'] = resource['frozen_balance_for_energy'] / 1_000_000
                if 'expire_time_for_energy' in resource:
                    expire_time = datetime.fromtimestamp(resource['expire_time_for_energy'] / 1000)
                    energy_info['locked'] = expire_time > datetime.now()
                    energy_info['expire_time'] = expire_time
            
            if 'frozen_balance_for_bandwidth' in resource:
                bandwidth_info['amount'] = resource['frozen_balance_for_bandwidth'] / 1_000_000
                if 'expire_time_for_bandwidth' in resource:
                    expire_time = datetime.fromtimestamp(resource['expire_time_for_bandwidth'] / 1000)
                    bandwidth_info['locked'] = expire_time > datetime.now()
                    bandwidth_info['expire_time'] = expire_time
        
        return energy_info, bandwidth_info
    
    def check_undelegation_status(
        self,
        owner_address: str,
        receiver_address: str,
        resource: str
    ) -> Dict:
        """Check if undelegation is possible"""
        
        energy_info, bandwidth_info = self.get_delegation_detail(
            owner_address,
            receiver_address
        )
        
        info = energy_info if resource == "ENERGY" else bandwidth_info
        
        if info['amount'] == 0:
            return {
                'can_undelegate': False,
                'reason': f'No {resource} delegated to this address',
                'amount': 0
            }
        
        if info['locked']:
            days_remaining = (info['expire_time'] - datetime.now()).days
            return {
                'can_undelegate': False,
                'reason': f'Locked for {days_remaining} more days',
                'amount': info['amount'],
                'unlock_time': info['expire_time']
            }
        
        return {
            'can_undelegate': True,
            'reason': 'Ready to undelegate',
            'amount': info['amount']
        }
    
    def get_all_delegations(self, owner_address: str) -> List[Dict]:
        """Get all active delegations with details"""
        
        receivers = self.get_delegation_index(owner_address)
        delegations = []
        
        for receiver in receivers:
            energy_info, bandwidth_info = self.get_delegation_detail(
                owner_address,
                receiver
            )
            
            delegations.append({
                'receiver': receiver,
                'energy': energy_info,
                'bandwidth': bandwidth_info,
                'total_delegated': energy_info['amount'] + bandwidth_info['amount']
            })
        
        return delegations
    
    def batch_undelegate(
        self,
        owner_address: str,
        requests: List[UndelegationRequest]
    ) -> List[Dict]:
        """Execute multiple undelegations"""
        
        results = []
        
        for req in requests:
            try:
                # Check status first
                status = self.check_undelegation_status(
                    owner_address,
                    req.receiver,
                    req.resource
                )
                
                if not status['can_undelegate']:
                    results.append({
                        'success': False,
                        'receiver': req.receiver,
                        'resource': req.resource,
                        'reason': status['reason']
                    })
                    continue
                
                # Determine amount
                amount = req.amount if req.amount else status['amount']
                
                # Execute undelegation
                tx = self.undelegate_resources(
                    owner_address,
                    req.receiver,
                    amount,
                    req.resource
                )
                
                results.append({
                    'success': True,
                    'receiver': req.receiver,
                    'resource': req.resource,
                    'amount': amount,
                    'txID': tx['txID']
                })
                
            except Exception as e:
                results.append({
                    'success': False,
                    'receiver': req.receiver,
                    'resource': req.resource,
                    'error': str(e)
                })
        
        return results
    
    def reclaim_all_unlocked(self, owner_address: str) -> Dict:
        """Reclaim all unlocked delegations"""
        
        delegations = self.get_all_delegations(owner_address)
        requests = []
        
        for delegation in delegations:
            # Check energy
            if delegation['energy']['amount'] > 0 and not delegation['energy']['locked']:
                requests.append(UndelegationRequest(
                    receiver=delegation['receiver'],
                    resource='ENERGY',
                    amount=delegation['energy']['amount']
                ))
            
            # Check bandwidth
            if delegation['bandwidth']['amount'] > 0 and not delegation['bandwidth']['locked']:
                requests.append(UndelegationRequest(
                    receiver=delegation['receiver'],
                    resource='BANDWIDTH',
                    amount=delegation['bandwidth']['amount']
                ))
        
        if not requests:
            return {
                'message': 'No unlocked delegations to reclaim',
                'total_reclaimed': 0,
                'transactions': []
            }
        
        results = self.batch_undelegate(owner_address, requests)
        
        total_reclaimed = sum(
            r['amount'] for r in results if r['success']
        )
        
        return {
            'message': f'Reclaimed {len(requests)} delegations',
            'total_reclaimed': total_reclaimed,
            'transactions': results
        }

class DelegationAnalyzer:
    """Analyze and optimize delegation efficiency"""
    
    def __init__(self, manager: TronUndelegationManager):
        self.manager = manager
    
    def analyze_utilization(
        self,
        owner_address: str
    ) -> List[Dict]:
        """Analyze delegation utilization rates"""
        
        delegations = self.manager.get_all_delegations(owner_address)
        analysis = []
        
        for delegation in delegations:
            # Get receiver's resource usage
            response = requests.post(
                f"{self.manager.base_url}/wallet/getaccountresource",
                json={
                    "address": delegation['receiver'],
                    "visible": True
                }
            )
            resources = response.json()
            
            # Calculate utilization
            energy_used = resources.get('EnergyUsed', 0)
            energy_limit = resources.get('EnergyLimit', 0)
            net_used = resources.get('NetUsed', 0)
            net_limit = resources.get('NetLimit', 0)
            
            energy_utilization = (energy_used / energy_limit * 100) if energy_limit > 0 else 0
            bandwidth_utilization = (net_used / net_limit * 100) if net_limit > 0 else 0
            
            analysis.append({
                'receiver': delegation['receiver'],
                'energy': {
                    'delegated_trx': delegation['energy']['amount'],
                    'utilization': f"{energy_utilization:.1f}%",
                    'utilization_rate': energy_utilization,
                    'locked': delegation['energy']['locked']
                },
                'bandwidth': {
                    'delegated_trx': delegation['bandwidth']['amount'],
                    'utilization': f"{bandwidth_utilization:.1f}%",
                    'utilization_rate': bandwidth_utilization,
                    'locked': delegation['bandwidth']['locked']
                }
            })
        
        return analysis
    
    def recommend_optimizations(
        self,
        owner_address: str,
        min_utilization: float = 30.0
    ) -> List[Dict]:
        """Recommend delegations to reclaim based on utilization"""
        
        analysis = self.analyze_utilization(owner_address)
        recommendations = []
        
        for item in analysis:
            # Energy recommendations
            if (item['energy']['delegated_trx'] > 0 and 
                item['energy']['utilization_rate'] < min_utilization and
                not item['energy']['locked']):
                
                recommendations.append({
                    'action': 'RECLAIM',
                    'receiver': item['receiver'],
                    'resource': 'ENERGY',
                    'amount': item['energy']['delegated_trx'],
                    'reason': f"Low utilization: {item['energy']['utilization']}",
                    'potential_savings': item['energy']['delegated_trx']
                })
            
            # Bandwidth recommendations
            if (item['bandwidth']['delegated_trx'] > 0 and
                item['bandwidth']['utilization_rate'] < min_utilization and
                not item['bandwidth']['locked']):
                
                recommendations.append({
                    'action': 'RECLAIM',
                    'receiver': item['receiver'],
                    'resource': 'BANDWIDTH',
                    'amount': item['bandwidth']['delegated_trx'],
                    'reason': f"Low utilization: {item['bandwidth']['utilization']}",
                    'potential_savings': item['bandwidth']['delegated_trx']
                })
        
        total_savings = sum(r['potential_savings'] for r in recommendations)
        
        return {
            'recommendations': recommendations,
            'total_potential_savings': total_savings,
            'summary': f"Can reclaim {total_savings:.2f} TRX from {len(recommendations)} inefficient delegations"
        }

# Example usage
def main():
    manager = TronUndelegationManager('YOUR_API_KEY')
    analyzer = DelegationAnalyzer(manager)
    
    owner_address = 'TOwnerAddress...'
    
    # 1. View all delegations
    print("=== Current Delegations ===")
    delegations = manager.get_all_delegations(owner_address)
    
    for d in delegations:
        print(f"\nTo: {d['receiver']}")
        print(f"  Energy: {d['energy']['amount']:.2f} TRX", 
              "(LOCKED)" if d['energy']['locked'] else "(UNLOCKED)")
        print(f"  Bandwidth: {d['bandwidth']['amount']:.2f} TRX",
              "(LOCKED)" if d['bandwidth']['locked'] else "(UNLOCKED)")
        print(f"  Total: {d['total_delegated']:.2f} TRX")
    
    # 2. Check specific undelegation
    print("\n=== Undelegation Status Check ===")
    status = manager.check_undelegation_status(
        owner_address,
        'TReceiverAddress...',
        'ENERGY'
    )
    print(f"Can undelegate: {status['can_undelegate']}")
    print(f"Reason: {status['reason']}")
    print(f"Amount available: {status['amount']:.2f} TRX")
    
    # 3. Analyze utilization
    print("\n=== Delegation Utilization Analysis ===")
    utilization = analyzer.analyze_utilization(owner_address)
    
    for u in utilization:
        print(f"\n{u['receiver']}:")
        print(f"  Energy: {u['energy']['delegated_trx']:.2f} TRX @ {u['energy']['utilization']} usage")
        print(f"  Bandwidth: {u['bandwidth']['delegated_trx']:.2f} TRX @ {u['bandwidth']['utilization']} usage")
    
    # 4. Get optimization recommendations
    print("\n=== Optimization Recommendations ===")
    recommendations = analyzer.recommend_optimizations(owner_address, 30.0)
    
    print(recommendations['summary'])
    for rec in recommendations['recommendations']:
        print(f"\n  • {rec['action']}: {rec['resource']} from {rec['receiver']}")
        print(f"    Amount: {rec['amount']:.2f} TRX")
        print(f"    Reason: {rec['reason']}")
    
    # 5. Reclaim all unlocked
    print("\n=== Reclaiming Unlocked Delegations ===")
    reclaim_result = manager.reclaim_all_unlocked(owner_address)
    
    print(reclaim_result['message'])
    print(f"Total reclaimed: {reclaim_result['total_reclaimed']:.2f} TRX")
    
    for tx in reclaim_result['transactions']:
        if tx['success']:
            print(f"  ✓ {tx['resource']} from {tx['receiver']}: {tx['amount']:.2f} TRX")
        else:
            print(f"  ✗ {tx['resource']} from {tx['receiver']}: {tx.get('reason', tx.get('error'))}")

if __name__ == "__main__":
    main()
```

## Undelegation Process Flow

```mermaid
graph LR
    A[Delegated Resources] --> B{Check Lock Status}
    B -->|Locked| C[Wait for Unlock]
    B -->|Unlocked| D[Initiate Undelegation]
    C --> D
    D --> E[Sign Transaction]
    E --> F[Broadcast]
    F --> G[Resources Returned to Owner]
    
    style A fill:#2196F3
    style B fill:#FF9800
    style G fill:#4CAF50
```

## Best Practices

### 1. **Check Lock Status First**

```javascript
// Always check before attempting undelegation
const status = await checkUndelegationStatus(owner, receiver, resource);
if (!status.canUndelegate) {
  console.log(`Cannot undelegate: ${status.reason}`);
  return;
}
```

### 2. **Monitor Utilization**

- Regularly check delegation efficiency
- Reclaim underutilized resources
- Redistribute based on actual needs

### 3. **Batch Operations**

- Group multiple undelegations together
- Reduces transaction costs
- Easier to manage

### 4. **Grace Period Management**

- Track lock expiration dates
- Set reminders for locked delegations
- Plan undelegations in advance

## Common Errors

| Error                            | Description                              | Solution                        |
| -------------------------------- | ---------------------------------------- | ------------------------------- |
| `No delegation found`            | No resources delegated to receiver       | Check delegation status first   |
| `Delegation is locked`           | Resources are locked for period          | Wait for lock period to expire  |
| `Insufficient delegated balance` | Trying to undelegate more than delegated | Check current delegation amount |
| `Invalid resource type`          | Must be BANDWIDTH or ENERGY              | Use correct resource string     |

## Use Cases

- **Resource Reallocation**: Move resources to more active users
- **Cost Optimization**: Reclaim resources from inactive accounts
- **Emergency Recovery**: Quickly reclaim resources when needed
- **Delegation Cleanup**: Remove old or unnecessary delegations
- **Efficiency Management**: Optimize resource distribution based on usage

## Related Methods

- [wallet/delegateresource](https://www.dwellir.com/docs/tron/wallet-delegateresource) - Delegate resources to others
- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Stake TRX for resources
- [wallet/unfreezebalancev2](https://www.dwellir.com/docs/tron/wallet-unfreezebalancev2) - Unstake TRX resources

---

## wallet/unfreezebalancev2 - Unstake TRX for Reso...

# wallet/unfreezebalancev2 - Unstake TRX for Reso...

Unstake (unfreeze) TRX to reclaim bandwidth or energy resources using TRON's Stake 2.0 mechanism. This is a native TRON wallet API endpoint -- there is no direct EVM-compatible (JSON-RPC) equivalent for staking operations.

TRON's bandwidth and energy model is central to its fee structure. Unlike Ethereum where every transaction burns gas, TRON users can stake TRX via [`wallet/freezebalancev2`](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) to obtain reusable energy and bandwidth, making transactions effectively free. Unstaking reverses this, reclaiming TRX at the cost of losing those resources after a 14-day waiting period.

## Endpoint

```
POST /wallet/unfreezebalancev2
```

## Request Parameters

- `owner_address` (`string, required`): Account address initiating unstaking (base58)
- `resource` (`string, required`): Resource type: "BANDWIDTH" or "ENERGY"
- `unfreeze_balance` (`number, required`): Amount to unstake in SUN (1 TRX = 1,000,000 SUN)

## Request Example

```bash
# Basic unstaking request for energy
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/unfreezebalancev2 \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TYourAddress...",
        "resource": "ENERGY",
        "unfreeze_balance": 1000000000,
        "visible": true
      }'

    # Unstake bandwidth
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/unfreezebalancev2 \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TYourAddress...",
        "resource": "BANDWIDTH",
        "unfreeze_balance": 500000000,
        "visible": true
      }'

    # Unstake delegated resources
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/unfreezebalancev2 \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TYourAddress...",
        "resource": "ENERGY",
        "unfreeze_balance": 2000000000,
        "receiver_address": "TReceiverAddress...",
        "visible": true
      }'

    # Check pending withdrawals (via getaccount)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccount \
      -H "Content-Type: application/json" \
      -d '{
        "address": "TYourAddress...",
        "visible": true
      }'

    # Withdraw expired unfrozen balance
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/withdrawexpireunfreeze \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TYourAddress...",
        "visible": true
      }'
```

## Response Fields

- `txID` (`string, required`): Transaction identifier for the unsigned unstake transaction.
- `raw_data` (`object, required`): Raw transaction payload, including contract, reference block data, and timestamps.
- `visible` (`boolean, optional`): Indicates whether address fields use Base58Check encoding.

## Successful Response

```json
{
  "visible": true,
  "txID": "8f3c4f9e2b8a7d6c5e4f3b2a1d9c8e7f6b5a4d3c2e1f9a8b7c6d5e4f3a2b1c9d",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "owner_address": "TYourAddress...",
            "unfreeze_balance": 1000000000,
            "resource": "ENERGY"
          },
          "type_url": "type.googleapis.com/protocol.UnfreezeBalanceV2Contract"
        },
        "type": "UnfreezeBalanceV2Contract"
      }
    ],
    "ref_block_bytes": "5a4b",
    "ref_block_hash": "3c2d4f9e8b7a6d5c",
    "expiration": 1702456849000,
    "timestamp": 1702456789000
  }
}
```

## Important Notes

### Unstaking Process

1. **14-Day Waiting Period**: After unstaking, TRX enters a 14-day withdrawal period
2. **No Resources During Wait**: Resources are lost immediately, TRX remains locked
3. **Manual Withdrawal**: After 14 days, must call `withdrawexpireunfreeze` to claim TRX
4. **Partial Unstaking**: Can unstake portions of staked amount

### Resource Implications

- Bandwidth/Energy is removed immediately upon unstaking
- Cannot re-stake the same TRX during withdrawal period
- Consider keeping minimum stake for basic operations

## Implementation Examples

cURL
JavaScript
Python

```bash
# Basic unstaking request for energy
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/unfreezebalancev2 \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TYourAddress...",
    "resource": "ENERGY",
    "unfreeze_balance": 1000000000,
    "visible": true
  }'

# Unstake bandwidth
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/unfreezebalancev2 \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TYourAddress...",
    "resource": "BANDWIDTH",
    "unfreeze_balance": 500000000,
    "visible": true
  }'

# Unstake delegated resources
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/unfreezebalancev2 \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TYourAddress...",
    "resource": "ENERGY",
    "unfreeze_balance": 2000000000,
    "receiver_address": "TReceiverAddress...",
    "visible": true
  }'

# Check pending withdrawals (via getaccount)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccount \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TYourAddress...",
    "visible": true
  }'

# Withdraw expired unfrozen balance
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/withdrawexpireunfreeze \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TYourAddress...",
    "visible": true
  }'
```

```javascript
class TronUnstakingManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }

  // Create unstaking transaction
  async createUnstakeTransaction(ownerAddress, resource, amountTRX) {
    const response = await fetch(`${this.baseUrl}/wallet/unfreezebalancev2`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        owner_address: ownerAddress,
        resource: resource,
        unfreeze_balance: amountTRX * 1000000, // Convert TRX to SUN
        visible: true
      })
    });

    if (!response.ok) {
      throw new Error(`Unstaking failed: ${response.statusText}`);
    }

    return response.json();
  }

  // Check pending withdrawals
  async getPendingWithdrawals(address) {
    const response = await fetch(`${this.baseUrl}/wallet/getaccount`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        address: address,
        visible: true
      })
    });

    const account = await response.json();
    
    // Parse unfreezing information
    const unfreezing = account.unfrozenV2 || [];
    return unfreezing.map(item => ({
      type: item.type,
      amount: item.unfreeze_amount / 1000000, // Convert to TRX
      expireTime: new Date(item.unfreeze_expire_time),
      canWithdraw: Date.now() > item.unfreeze_expire_time
    }));
  }

  // Calculate optimal unstaking amount
  async calculateOptimalUnstake(address, targetResourceReduction) {
    const response = await fetch(`${this.baseUrl}/wallet/getaccountresource`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        address: address,
        visible: true
      })
    });

    const resources = await response.json();
    
    // Calculate based on current resource usage
    const energyStaked = resources.EnergyLimit || 0;
    const bandwidthStaked = resources.NetLimit || 0;
    
    return {
      energy: {
        current: energyStaked,
        toUnstake: Math.floor(energyStaked * targetResourceReduction),
        remaining: energyStaked * (1 - targetResourceReduction)
      },
      bandwidth: {
        current: bandwidthStaked,
        toUnstake: Math.floor(bandwidthStaked * targetResourceReduction),
        remaining: bandwidthStaked * (1 - targetResourceReduction)
      }
    };
  }

  // Withdraw expired unfrozen balance
  async withdrawExpiredBalance(ownerAddress) {
    const response = await fetch(`${this.baseUrl}/wallet/withdrawexpireunfreeze`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        owner_address: ownerAddress,
        visible: true
      })
    });

    if (!response.ok) {
      throw new Error(`Withdrawal failed: ${response.statusText}`);
    }

    return response.json();
  }
}

// Example usage
async function manageUnstaking() {
  const manager = new TronUnstakingManager('YOUR_API_KEY');
  
  try {
    // Check pending withdrawals first
    const pending = await manager.getPendingWithdrawals('TYourAddress...');
    console.log('Pending withdrawals:', pending);
    
    // Withdraw any expired funds
    const withdrawable = pending.filter(p => p.canWithdraw);
    if (withdrawable.length > 0) {
      const withdrawal = await manager.withdrawExpiredBalance('TYourAddress...');
      console.log('Withdrawal transaction:', withdrawal);
    }
    
    // Calculate optimal unstaking (reduce resources by 30%)
    const optimal = await manager.calculateOptimalUnstake('TYourAddress...', 0.3);
    console.log('Optimal unstaking amounts:', optimal);
    
    // Create unstaking transaction for energy
    const unstakeTx = await manager.createUnstakeTransaction(
      'TYourAddress...',
      'ENERGY',
      optimal.energy.toUnstake / 28.5 // Convert energy to TRX (approximate ratio)
    );
    
    console.log('Unstaking transaction created:', unstakeTx.txID);
    console.log('Sign and broadcast this transaction to complete unstaking');
    
  } catch (error) {
    console.error('Unstaking error:', error);
  }
}
```

```python
import requests
import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional

class TronUnstakingManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
    
    def create_unstake_transaction(
        self, 
        owner_address: str, 
        resource: str, 
        amount_trx: float
    ) -> Dict:
        """Create an unstaking transaction"""
        
        response = requests.post(
            f"{self.base_url}/wallet/unfreezebalancev2",
            json={
                "owner_address": owner_address,
                "resource": resource,
                "unfreeze_balance": int(amount_trx * 1_000_000),  # Convert to SUN
                "visible": True
            }
        )
        response.raise_for_status()
        return response.json()
    
    def get_pending_withdrawals(self, address: str) -> List[Dict]:
        """Check pending withdrawal amounts and times"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getaccount",
            json={
                "address": address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        account = response.json()
        unfreezing = account.get('unfrozenV2', [])
        
        withdrawals = []
        for item in unfreezing:
            expire_time = datetime.fromtimestamp(item['unfreeze_expire_time'] / 1000)
            withdrawals.append({
                'type': item.get('type', 'UNKNOWN'),
                'amount_trx': item['unfreeze_amount'] / 1_000_000,
                'expire_time': expire_time,
                'can_withdraw': datetime.now() > expire_time,
                'days_remaining': max(0, (expire_time - datetime.now()).days)
            })
        
        return withdrawals
    
    def calculate_resource_impact(
        self, 
        address: str, 
        unstake_amount: float,
        resource_type: str
    ) -> Dict:
        """Calculate the impact of unstaking on available resources"""
        
        # Get current resources
        response = requests.post(
            f"{self.base_url}/wallet/getaccountresource",
            json={
                "address": address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        resources = response.json()
        
        if resource_type == "ENERGY":
            current = resources.get('EnergyLimit', 0)
            ratio = 28.5  # Approximate TRX to energy ratio
            reduction = unstake_amount * ratio
            
            return {
                'resource_type': 'ENERGY',
                'current_amount': current,
                'reduction': reduction,
                'remaining': max(0, current - reduction),
                'percentage_reduction': (reduction / current * 100) if current > 0 else 0
            }
        
        elif resource_type == "BANDWIDTH":
            current = resources.get('NetLimit', 0)
            ratio = 1  # 1 TRX = 1 bandwidth
            reduction = unstake_amount * ratio
            
            return {
                'resource_type': 'BANDWIDTH',
                'current_amount': current,
                'reduction': reduction,
                'remaining': max(0, current - reduction),
                'percentage_reduction': (reduction / current * 100) if current > 0 else 0
            }
    
    def batch_unstake(
        self, 
        owner_address: str,
        unstake_plan: Dict[str, float]
    ) -> List[Dict]:
        """Create multiple unstaking transactions"""
        
        transactions = []
        
        for resource, amount in unstake_plan.items():
            if amount > 0:
                tx = self.create_unstake_transaction(
                    owner_address,
                    resource,
                    amount
                )
                transactions.append({
                    'resource': resource,
                    'amount': amount,
                    'txID': tx['txID'],
                    'transaction': tx
                })
        
        return transactions
    
    def withdraw_expired_balance(self, owner_address: str) -> Optional[Dict]:
        """Withdraw expired unfrozen balance"""
        
        # Check if there's anything to withdraw
        withdrawals = self.get_pending_withdrawals(owner_address)
        withdrawable = [w for w in withdrawals if w['can_withdraw']]
        
        if not withdrawable:
            return None
        
        response = requests.post(
            f"{self.base_url}/wallet/withdrawexpireunfreeze",
            json={
                "owner_address": owner_address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        result = response.json()
        result['withdrawn_amount'] = sum(w['amount_trx'] for w in withdrawable)
        return result

# Example usage with monitoring
def monitor_unstaking_lifecycle():
    manager = TronUnstakingManager('YOUR_API_KEY')
    address = 'TYourAddress...'
    
    # 1. Check current unstaking status
    print("=== Unstaking Status ===")
    withdrawals = manager.get_pending_withdrawals(address)
    
    for w in withdrawals:
        status = "READY TO WITHDRAW" if w['can_withdraw'] else f"{w['days_remaining']} days remaining"
        print(f"{w['type']}: {w['amount_trx']:.2f} TRX - {status}")
    
    # 2. Withdraw any expired amounts
    if any(w['can_withdraw'] for w in withdrawals):
        print("\n=== Processing Withdrawals ===")
        withdrawal_tx = manager.withdraw_expired_balance(address)
        if withdrawal_tx:
            print(f"Withdrawal TX: {withdrawal_tx['txID']}")
            print(f"Amount: {withdrawal_tx['withdrawn_amount']:.2f} TRX")
    
    # 3. Calculate impact before unstaking
    print("\n=== Unstaking Impact Analysis ===")
    energy_impact = manager.calculate_resource_impact(address, 1000, "ENERGY")
    bandwidth_impact = manager.calculate_resource_impact(address, 500, "BANDWIDTH")
    
    print(f"Energy Impact: {energy_impact['percentage_reduction']:.1f}% reduction")
    print(f"Bandwidth Impact: {bandwidth_impact['percentage_reduction']:.1f}% reduction")
    
    # 4. Create unstaking plan
    unstake_plan = {
        "ENERGY": 1000,  # Unstake 1000 TRX from energy
        "BANDWIDTH": 500  # Unstake 500 TRX from bandwidth
    }
    
    print("\n=== Creating Unstaking Transactions ===")
    transactions = manager.batch_unstake(address, unstake_plan)
    
    for tx in transactions:
        print(f"{tx['resource']}: Unstaking {tx['amount']} TRX")
        print(f"Transaction ID: {tx['txID']}")
        print("Note: Transaction must be signed and broadcast")

if __name__ == "__main__":
    monitor_unstaking_lifecycle()
```

## Unstaking Timeline

```mermaid
graph LR
    A[Staked TRX] --> B[Initiate Unstaking]
    B --> C[14-Day Waiting Period]
    C --> D[Withdrawal Available]
    D --> E[Execute Withdrawal]
    E --> F[TRX in Wallet]
    
    style A fill:#4CAF50
    style C fill:#FF9800
    style F fill:#2196F3
```

## Best Practices

### 1. **Plan Unstaking Carefully**

- Resources are lost immediately
- Cannot re-stake during withdrawal period
- Keep minimum stake for basic operations

### 2. **Monitor Withdrawal Periods**

- Track 14-day waiting periods
- Set reminders for withdrawal dates
- Batch withdrawals for efficiency

### 3. **Resource Management**

```javascript
// Keep minimum operational resources
const MIN_ENERGY_STAKE = 5000; // TRX
const MIN_BANDWIDTH_STAKE = 1000; // TRX

function calculateSafeUnstake(current, minimum) {
  return Math.max(0, current - minimum);
}
```

### 4. **Error Handling**

- Check account has staked balance
- Verify resource type is correct
- Handle insufficient stake errors

## Common Errors

| Error                         | Description                           | Solution                    |
| ----------------------------- | ------------------------------------- | --------------------------- |
| `No frozen balance`           | Account has no staked TRX             | Check staking status first  |
| `Invalid resource type`       | Resource must be BANDWIDTH or ENERGY  | Use correct resource string |
| `Insufficient frozen balance` | Trying to unstake more than available | Check current stake amount  |
| `Invalid address`             | Malformed TRON address                | Verify base58 format        |

## Use Cases

- **Resource Optimization**: Unstake excess resources not being used
- **Liquidity Management**: Free up TRX for trading or transfers
- **Delegation Cleanup**: Reclaim delegated resources from inactive accounts
- **Portfolio Rebalancing**: Adjust resource allocation between bandwidth/energy
- **Emergency Liquidity**: Access staked TRX when needed (with 14-day delay)

## Related Methods

- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Stake TRX for resources
- [wallet/getaccountresource](https://www.dwellir.com/docs/tron/wallet-getaccountresource) - Check resource status
- [wallet/delegateresource](https://www.dwellir.com/docs/tron/wallet-delegateresource) - Delegate resources to others

---

## wallet/validateaddress - Validate TRON Address

# wallet/validateaddress - Validate TRON Address

**Dwellir's TRON infrastructure** provides fast address validation with format checking and encoding verification.
Ensure address validity before processing transactions or queries.

[Start validating addresses](https://dashboard.dwellir.com/register)

Validate a TRON address to check if it's properly formatted and valid on the network. Supports both Base58 (T-prefix, 34 characters) and Hexadecimal (41-prefix, 42 characters) address formats. This is a native TRON wallet API endpoint with no EVM-compatible JSON-RPC equivalent.

### TRON Address Formats

| Format | Prefix | Length   | Example                                      |
| ------ | ------ | -------- | -------------------------------------------- |
| Base58 | `T`    | 34 chars | `TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF`         |
| Hex    | `41`   | 42 chars | `41E552F6487585C2B58BC2C9BB4492BC1F17132CD0` |

Both formats represent the same underlying 21-byte address. The EVM-compatible JSON-RPC layer uses standard 20-byte hex addresses (without the `41` prefix).

## Use Cases

`wallet/validateaddress` is essential for:

- **Input Validation** - Verify user-provided addresses
- **Transaction Safety** - Validate recipient before sending
- **Form Validation** - Real-time address checking in UIs
- **API Security** - Validate addresses in API requests
- **Data Integrity** - Ensure address validity in databases

## Request Parameters

- `address` (`string, required`): TRON address to validate (Base58 or Hex)
- `visible` (`boolean, optional`): Format type - true for Base58, false for Hex (default: true)

## Request Example

```json
{
  "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
  "visible": true
}
```

## Response Fields

- `result` (`boolean, required`): Whether the address is valid
- `message` (`string, required`): Validation result message

## Successful Response

```json
{
  "result": true,
  "message": "Base58check format"
}
```

## Error Responses

### Error 1

- Description: Invalid address format

### Error 2

- Description: Wrong address length

### Error 3

- Description: Invalid characters

### Error 4

- Description: API connection failed

## Implementation Examples

cURL
JavaScript
Python

```bash
# Validate Base58 address
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/validateaddress" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }'

# Validate Hex address
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/validateaddress" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "41E552F6487585C2B58BC2C9BB4492BC1F17132CD0",
    "visible": false
  }'

# Validate invalid address
curl -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/validateaddress" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "InvalidAddress123",
    "visible": true
  }'

# Validate and parse result with jq
curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/validateaddress" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF",
    "visible": true
  }' | jq '{
    is_valid: .result,
    validation_message: .message
  }'

# Batch validation script
#!/bin/bash
API_KEY="YOUR_API_KEY"
ADDRESSES=(
  "TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF"
  "TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh"
  "InvalidAddress"
)

for addr in "${ADDRESSES[@]}"; do
  echo "Validating: $addr"
  curl -s -X POST "https://api-tron-mainnet.n.dwellir.com/$API_KEY/wallet/validateaddress" \
    -H "Content-Type: application/json" \
    -d "{\"address\": \"$addr\", \"visible\": true}" | \
    jq -r 'if .result then "✓ Valid" else "✗ Invalid: " + .message end'
  echo ""
done
```

```javascript
const TRON_API = 'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY';

// Basic address validation
async function validateAddress(address) {
  const response = await fetch(`${TRON_API}/wallet/validateaddress`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      address: address,
      visible: true
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  return await response.json();
}

// Advanced address validator class
class TronAddressValidator {
  constructor(apiKey) {
    this.apiUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
    this.cache = new Map();
    this.cacheTimeout = 60000; // 1 minute cache
  }
  
  async validate(address, useCache = true) {
    // Check cache first
    if (useCache && this.cache.has(address)) {
      const cached = this.cache.get(address);
      if (Date.now() - cached.timestamp < this.cacheTimeout) {
        return cached.result;
      }
    }
    
    // Perform basic format check first
    const formatValid = this.checkFormat(address);
    if (!formatValid.valid) {
      return {
        result: false,
        message: formatValid.message,
        format: formatValid.format
      };
    }
    
    // Call API for full validation
    try {
      const response = await fetch(`${this.apiUrl}/wallet/validateaddress`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          address: address,
          visible: formatValid.format === 'base58'
        })
      });
      
      const result = await response.json();
      
      // Cache the result
      if (useCache) {
        this.cache.set(address, {
          result: result,
          timestamp: Date.now()
        });
      }
      
      return result;
    } catch (error) {
      console.error('Validation API error:', error);
      return {
        result: false,
        message: 'API validation failed',
        error: error.message
      };
    }
  }
  
  checkFormat(address) {
    // Base58 format check (starts with T, 34 characters)
    if (address.startsWith('T') && address.length === 34) {
      // Check for valid Base58 characters
      const base58Regex = /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/;
      if (base58Regex.test(address)) {
        return { valid: true, format: 'base58' };
      }
      return { 
        valid: false, 
        format: 'base58',
        message: 'Invalid Base58 characters' 
      };
    }
    
    // Hex format check (41 prefix, 42 characters)
    if (address.startsWith('41') && address.length === 42) {
      const hexRegex = /^[0-9a-fA-F]+$/;
      if (hexRegex.test(address)) {
        return { valid: true, format: 'hex' };
      }
      return { 
        valid: false, 
        format: 'hex',
        message: 'Invalid hexadecimal characters' 
      };
    }
    
    return { 
      valid: false, 
      format: 'unknown',
      message: 'Invalid TRON address format' 
    };
  }
  
  async validateBatch(addresses) {
    const results = await Promise.allSettled(
      addresses.map(addr => this.validate(addr))
    );
    
    return results.map((result, index) => ({
      address: addresses[index],
      valid: result.status === 'fulfilled' && result.value.result,
      details: result.status === 'fulfilled' ? result.value : null,
      error: result.status === 'rejected' ? result.reason : null
    }));
  }
  
  // Convert between formats
  async convertFormat(address) {
    const validation = await this.validate(address);
    if (!validation.result) {
      return { error: 'Invalid address', validation };
    }
    
    const format = this.checkFormat(address);
    
    // Note: Actual conversion requires base58/hex encoding libraries
    // This is a placeholder for the conversion logic
    return {
      original: address,
      format: format.format,
      converted: format.format === 'base58' ? 
        this.toHex(address) : 
        this.toBase58(address)
    };
  }
  
  toHex(base58Address) {
    // Placeholder - actual implementation needs base58 decoder
    return '41' + '0'.repeat(40); 
  }
  
  toBase58(hexAddress) {
    // Placeholder - actual implementation needs base58 encoder
    return 'T' + 'x'.repeat(33);
  }
}

// Form validation helper
class FormValidator {
  constructor(apiKey) {
    this.validator = new TronAddressValidator(apiKey);
    this.debounceTimer = null;
  }
  
  async validateInput(inputElement, feedbackElement) {
    const address = inputElement.value.trim();
    
    // Clear previous timer
    clearTimeout(this.debounceTimer);
    
    // Quick format check
    const formatCheck = this.validator.checkFormat(address);
    
    if (!address) {
      this.updateFeedback(feedbackElement, 'empty', 'Enter a TRON address');
      return false;
    }
    
    if (!formatCheck.valid) {
      this.updateFeedback(feedbackElement, 'invalid', formatCheck.message);
      return false;
    }
    
    // Show validating state
    this.updateFeedback(feedbackElement, 'validating', 'Validating address...');
    
    // Debounce API call
    this.debounceTimer = setTimeout(async () => {
      try {
        const result = await this.validator.validate(address);
        
        if (result.result) {
          this.updateFeedback(feedbackElement, 'valid', 'Valid TRON address');
          return true;
        } else {
          this.updateFeedback(feedbackElement, 'invalid', result.message);
          return false;
        }
      } catch (error) {
        this.updateFeedback(feedbackElement, 'error', 'Validation failed');
        return false;
      }
    }, 500);
  }
  
  updateFeedback(element, status, message) {
    element.textContent = message;
    element.className = `feedback feedback-${status}`;
  }
}

// Usage examples
(async () => {
  const validator = new TronAddressValidator('YOUR_API_KEY');
  
  try {
    // Validate single address
    const result = await validator.validate('TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF');
    console.log('Address valid:', result.result);
    
    // Validate batch of addresses
    const addresses = [
      'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF',
      'InvalidAddress123',
      'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh'
    ];
    
    const batchResults = await validator.validateBatch(addresses);
    batchResults.forEach(result => {
      console.log(`${result.address}: ${result.valid ? 'Valid' : 'Invalid'}`);
    });
    
    // Form validation example
    const formValidator = new FormValidator('YOUR_API_KEY');
    const input = document.getElementById('addressInput');
    const feedback = document.getElementById('feedback');
    
    input?.addEventListener('input', () => {
      formValidator.validateInput(input, feedback);
    });
    
  } catch (error) {
    console.error('Validation error:', error);
  }
})();
```

```python
import requests
import re
from typing import Dict, List, Optional, Tuple
from time import time
from threading import Lock

class TronAddressValidator:
    def __init__(self, api_key: str):
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
        self.headers = {'Content-Type': 'application/json'}
        self.cache = {}
        self.cache_timeout = 60  # seconds
        self.cache_lock = Lock()
    
    def validate_address(
        self, 
        address: str, 
        visible: bool = True,
        use_cache: bool = True
    ) -> Dict:
        """
        Validate a TRON address via API
        """
        # Check cache first
        if use_cache:
            cached = self._get_cached(address)
            if cached:
                return cached
        
        # Perform format validation first
        format_check = self.check_format(address)
        if not format_check['valid']:
            return {
                'result': False,
                'message': format_check['message'],
                'format': format_check['format']
            }
        
        # API validation
        url = f"{self.base_url}/wallet/validateaddress"
        payload = {
            "address": address,
            "visible": visible
        }
        
        try:
            response = requests.post(url, headers=self.headers, json=payload)
            response.raise_for_status()
            result = response.json()
            
            # Cache the result
            if use_cache:
                self._cache_result(address, result)
            
            return result
            
        except requests.RequestException as e:
            return {
                'result': False,
                'message': f'API validation failed: {str(e)}',
                'error': str(e)
            }
    
    def check_format(self, address: str) -> Dict:
        """
        Check address format without API call
        """
        # Base58 format (starts with T, 34 characters)
        if address.startswith('T') and len(address) == 34:
            # Valid Base58 characters
            base58_chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
            if all(c in base58_chars for c in address):
                return {'valid': True, 'format': 'base58'}
            return {
                'valid': False,
                'format': 'base58',
                'message': 'Invalid Base58 characters'
            }
        
        # Hex format (starts with 41, 42 characters)
        if address.startswith('41') and len(address) == 42:
            if re.match(r'^[0-9a-fA-F]+$', address):
                return {'valid': True, 'format': 'hex'}
            return {
                'valid': False,
                'format': 'hex',
                'message': 'Invalid hexadecimal characters'
            }
        
        return {
            'valid': False,
            'format': 'unknown',
            'message': 'Invalid TRON address format'
        }
    
    def validate_batch(self, addresses: List[str]) -> List[Dict]:
        """
        Validate multiple addresses
        """
        results = []
        
        for address in addresses:
            result = self.validate_address(address)
            results.append({
                'address': address,
                'valid': result.get('result', False),
                'message': result.get('message', ''),
                'format': self.check_format(address)['format']
            })
        
        return results
    
    def _get_cached(self, address: str) -> Optional[Dict]:
        """
        Get cached validation result
        """
        with self.cache_lock:
            if address in self.cache:
                cached_time, result = self.cache[address]
                if time() - cached_time < self.cache_timeout:
                    return result
                else:
                    del self.cache[address]
        return None
    
    def _cache_result(self, address: str, result: Dict):
        """
        Cache validation result
        """
        with self.cache_lock:
            self.cache[address] = (time(), result)
    
    def clear_cache(self):
        """
        Clear validation cache
        """
        with self.cache_lock:
            self.cache.clear()
    
    def is_valid_checksum(self, address: str) -> bool:
        """
        Additional checksum validation (simplified)
        Note: Full implementation requires base58 decoding
        """
        format_check = self.check_format(address)
        if not format_check['valid']:
            return False
        
        # For demonstration - actual checksum validation
        # would require proper base58/hex decoding
        return format_check['valid']

class AddressValidationService:
    """
    High-level validation service with additional features
    """
    def __init__(self, api_key: str):
        self.validator = TronAddressValidator(api_key)
        self.stats = {
            'total_validated': 0,
            'valid_count': 0,
            'invalid_count': 0
        }
    
    def validate_with_stats(self, address: str) -> Dict:
        """
        Validate and track statistics
        """
        result = self.validator.validate_address(address)
        
        self.stats['total_validated'] += 1
        if result.get('result'):
            self.stats['valid_count'] += 1
        else:
            self.stats['invalid_count'] += 1
        
        return result
    
    def validate_and_suggest(self, address: str) -> Dict:
        """
        Validate and provide suggestions for invalid addresses
        """
        result = self.validator.validate_address(address)
        
        if not result.get('result'):
            format_check = self.validator.check_format(address)
            
            suggestions = []
            if format_check['format'] == 'unknown':
                if len(address) == 34 and not address.startswith('T'):
                    suggestions.append('TRON addresses should start with "T"')
                elif len(address) == 42 and not address.startswith('41'):
                    suggestions.append('Hex addresses should start with "41"')
                else:
                    suggestions.append('Check address length (34 for Base58, 42 for Hex)')
            
            result['suggestions'] = suggestions
        
        return result
    
    def get_statistics(self) -> Dict:
        """
        Get validation statistics
        """
        total = self.stats['total_validated']
        if total == 0:
            return self.stats
        
        return {
            **self.stats,
            'valid_percentage': (self.stats['valid_count'] / total) * 100,
            'invalid_percentage': (self.stats['invalid_count'] / total) * 100
        }

# Usage examples
if __name__ == "__main__":
    validator = TronAddressValidator('YOUR_API_KEY')
    service = AddressValidationService('YOUR_API_KEY')
    
    try:
        # Single address validation
        result = validator.validate_address('TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF')
        print(f"Address valid: {result.get('result')}")
        
        # Format checking
        format_check = validator.check_format('TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF')
        print(f"Format: {format_check['format']}, Valid: {format_check['valid']}")
        
        # Batch validation
        addresses = [
            'TNPdqto8HiuMzoG7Vv9wyyYhWzCojLeHAF',
            'InvalidAddress',
            '41E552F6487585C2B58BC2C9BB4492BC1F17132CD0',
            'TJmmqjb1DK9TTZbQXzRQ2AuA94z4gKAPFh'
        ]
        
        batch_results = validator.validate_batch(addresses)
        for result in batch_results:
            status = "✓" if result['valid'] else "✗"
            print(f"{status} {result['address'][:10]}... : {result['format']}")
        
        # Validation with suggestions
        invalid_result = service.validate_and_suggest('XRX6Q82wMqWNbCCmJPLz9mR8AZwqvUU2pN')
        if not invalid_result.get('result'):
            print("Invalid address. Suggestions:")
            for suggestion in invalid_result.get('suggestions', []):
                print(f"  - {suggestion}")
        
        # Get statistics
        stats = service.get_statistics()
        print(f"\nValidation Statistics:")
        print(f"  Total: {stats['total_validated']}")
        print(f"  Valid: {stats['valid_count']} ({stats.get('valid_percentage', 0):.1f}%)")
        print(f"  Invalid: {stats['invalid_count']} ({stats.get('invalid_percentage', 0):.1f}%)")
        
    except Exception as e:
        print(f"Error: {e}")
```

## Response Examples

### Valid Address Response

```json
{
  "result": true,
  "message": "Valid address"
}
```

### Invalid Address Response

```json
{
  "result": false,
  "message": "Invalid address format"
}
```

### Malformed Address Response

```json
{
  "result": false,
  "message": "Illegal address"
}
```

## Common Use Cases

### 1. Form Input Validation

```javascript
function setupAddressValidation() {
  const input = document.getElementById('addressInput');
  const submitBtn = document.getElementById('submitBtn');
  const feedback = document.getElementById('feedback');
  
  let isValid = false;
  
  input.addEventListener('input', async (e) => {
    const address = e.target.value.trim();
    
    if (!address) {
      feedback.textContent = '';
      submitBtn.disabled = true;
      return;
    }
    
    // Quick format check
    if (!address.startsWith('T') || address.length !== 34) {
      feedback.textContent = '❌ Invalid format';
      feedback.className = 'error';
      submitBtn.disabled = true;
      return;
    }
    
    // API validation
    try {
      const result = await validateAddress(address);
      
      if (result.result) {
        feedback.textContent = '✓ Valid address';
        feedback.className = 'success';
        isValid = true;
      } else {
        feedback.textContent = '❌ ' + result.message;
        feedback.className = 'error';
        isValid = false;
      }
      
      submitBtn.disabled = !isValid;
    } catch (error) {
      feedback.textContent = '⚠️ Validation error';
      feedback.className = 'warning';
      submitBtn.disabled = true;
    }
  });
}
```

### 2. Transaction Pre-validation

```javascript
async function sendTransaction(toAddress, amount) {
  // Validate address before sending
  const validation = await validateAddress(toAddress);
  
  if (!validation.result) {
    throw new Error(`Invalid recipient address: ${validation.message}`);
  }
  
  // Proceed with transaction
  return createTransaction(toAddress, amount);
}
```

### 3. Bulk Address Import

```javascript
async function importAddresses(addressList) {
  const results = {
    valid: [],
    invalid: []
  };
  
  for (const address of addressList) {
    const validation = await validateAddress(address);
    
    if (validation.result) {
      results.valid.push(address);
    } else {
      results.invalid.push({
        address,
        reason: validation.message
      });
    }
  }
  
  return results;
}
```

## Best Practices

1. **Cache Results** - Cache validation results for 60 seconds
2. **Format Check First** - Validate format locally before API call
3. **Debounce Input** - Debounce validation on user input
4. **Batch Validation** - Validate multiple addresses in parallel
5. **Error Handling** - Gracefully handle validation failures

## Related Methods

- [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount) - Get account information
- [wallet/getaccountbalance](https://www.dwellir.com/docs/tron/wallet-getaccountbalance) - Get account balance
- [wallet/createtransaction](https://www.dwellir.com/docs/tron/wallet-createtransaction) - Create TRX transfer (validate addresses first)

---

## wallet/votewitnessaccount - Vote for Super Repr...

# wallet/votewitnessaccount - Vote for Super Repr...

Vote for Super Representatives using TRX voting power from frozen balance.

## Endpoint

```
POST /wallet/votewitnessaccount
```

## Request Parameters

- `owner_address` (`string, required`): Required parameter: Voter's account address (base58)
- `votes` (`array, required`): Required parameter: Array of vote objects with SR address and vote count
- `permission_id` (`number, required`): Optional parameter: Permission ID for multi-signature (default: 0)
- `visible` (`boolean, required`): Optional parameter: Return base58 addresses (default: false returns hex)

## Request Example

```bash
# Vote for single SR
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TVoterAddress...",
        "votes": [
          {
            "vote_address": "TSRAddress...",
            "vote_count": 1000000
          }
        ],
        "visible": true
      }'

    # Vote for multiple SRs
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TVoterAddress...",
        "votes": [
          {
            "vote_address": "TSR1Address...",
            "vote_count": 500000
          },
          {
            "vote_address": "TSR2Address...",
            "vote_count": 300000
          },
          {
            "vote_address": "TSR3Address...",
            "vote_count": 200000
          }
        ],
        "visible": true
      }'

    # Clear all votes
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TVoterAddress...",
        "votes": [],
        "visible": true
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `txID` - Transaction hash `raw_data` - Transaction raw data `contract` - Voting contract details `expiration` - Transaction expiration timestamp `timestamp` - Transaction creation timestamp `visible` - Address format indicator

## Successful Response

```json
{
  "visible": true,
  "txID": "f9e8d7c6b5a4e3d2c1b0a9f8e7d6c5b4a3d2c1e0f9e8d7c6b5a4e3d2c1b0a9f8",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "owner_address": "TVoterAddress...",
            "votes": [
              {
                "vote_address": "TSRAddress...",
                "vote_count": 1000000
              }
            ]
          },
          "type_url": "type.googleapis.com/protocol.VoteWitnessContract"
        },
        "type": "VoteWitnessContract"
      }
    ],
    "ref_block_bytes": "8d7e",
    "ref_block_hash": "6f5a9b8c7d6e5f4a",
    "expiration": 1702456849000,
    "timestamp": 1702456789000
  }
}
```

## Important Notes

### Voting Rules

1. **Voting Power**: 1 frozen TRX = 1 vote
2. **Vote Distribution**: Can split votes among multiple SRs
3. **Vote Persistence**: Votes remain until changed or TRX unfrozen
4. **Immediate Effect**: Votes count immediately after confirmation
5. **Rewards**: Voting rewards distributed daily based on SR performance

## Implementation Examples

cURL
JavaScript
Python

```bash
# Vote for single SR
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TVoterAddress...",
    "votes": [
      {
        "vote_address": "TSRAddress...",
        "vote_count": 1000000
      }
    ],
    "visible": true
  }'

# Vote for multiple SRs
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TVoterAddress...",
    "votes": [
      {
        "vote_address": "TSR1Address...",
        "vote_count": 500000
      },
      {
        "vote_address": "TSR2Address...",
        "vote_count": 300000
      },
      {
        "vote_address": "TSR3Address...",
        "vote_count": 200000
      }
    ],
    "visible": true
  }'

# Clear all votes
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TVoterAddress...",
    "votes": [],
    "visible": true
  }'
```

```javascript
// Vote for single SR
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    owner_address: 'TVoterAddress...',
    votes: [
      {
        vote_address: 'TSRAddress...',
        vote_count: 1000000  // 1M votes
      }
    ],
    visible: true
  }),
});

const transaction = await response.json();
console.log('Vote transaction created:', transaction.txID);

// Vote for multiple SRs
const multiVoteResponse = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    owner_address: 'TVoterAddress...',
    votes: [
      {
        vote_address: 'TSR1Address...',
        vote_count: 500000
      },
      {
        vote_address: 'TSR2Address...',
        vote_count: 300000
      },
      {
        vote_address: 'TSR3Address...',
        vote_count: 200000
      }
    ],
    visible: true
  }),
});

const multiVoteTx = await multiVoteResponse.json();
console.log('Multi-vote transaction:', multiVoteTx.txID);

// Clear all votes (vote with empty array)
const clearVotesResponse = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    owner_address: 'TVoterAddress...',
    votes: [],
    visible: true
  }),
});
```

```python
import requests

url = "https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/votewitnessaccount"

# Vote for single SR
single_vote = {
    "owner_address": "TVoterAddress...",
    "votes": [
        {
            "vote_address": "TSRAddress...",
            "vote_count": 1000000  # 1M votes
        }
    ],
    "visible": True
}

response = requests.post(url, json=single_vote)
print(f"Single vote TX: {response.json()['txID']}")

# Vote for multiple SRs with weighted distribution
multi_vote = {
    "owner_address": "TVoterAddress...",
    "votes": [
        {
            "vote_address": "TSR1Address...",
            "vote_count": 600000  # 60% of votes
        },
        {
            "vote_address": "TSR2Address...",
            "vote_count": 300000  # 30% of votes
        },
        {
            "vote_address": "TSR3Address...",
            "vote_count": 100000  # 10% of votes
        }
    ],
    "visible": True
}

multi_response = requests.post(url, json=multi_vote)
print(f"Multi-vote TX: {multi_response.json()['txID']}")

# Update existing votes
update_vote = {
    "owner_address": "TVoterAddress...",
    "votes": [
        {
            "vote_address": "TNewSRAddress...",
            "vote_count": 1000000
        }
    ],
    "visible": True
}

update_response = requests.post(url, json=update_vote)
print(f"Updated votes TX: {update_response.json()['txID']}")
```

## Voting Strategies

```javascript
class VotingStrategy {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
  }

  // Get available voting power
  async getVotingPower(address) {
    const response = await fetch(`${this.baseUrl}/wallet/getaccount`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ address, visible: true })
    });
    
    const account = await response.json();
    const frozenTRX = account.frozen?.[0]?.frozen_balance || 0;
    return frozenTRX / 1000000; // Convert to TRX
  }

  // Calculate optimal vote distribution
  async optimizeVotes(voterAddress, srAddresses, strategy = 'balanced') {
    const votingPower = await this.getVotingPower(voterAddress);
    
    if (strategy === 'balanced') {
      // Equal distribution
      const votePerSR = Math.floor(votingPower / srAddresses.length);
      return srAddresses.map(sr => ({
        vote_address: sr,
        vote_count: votePerSR
      }));
    } else if (strategy === 'weighted') {
      // Weighted by SR performance
      const witnesses = await this.getWitnesses();
      const selectedSRs = witnesses.filter(w => srAddresses.includes(w.address));
      
      // Weight by reliability
      const totalReliability = selectedSRs.reduce((sum, sr) => {
        const reliability = sr.totalProduced / (sr.totalProduced + sr.totalMissed);
        return sum + reliability;
      }, 0);
      
      return selectedSRs.map(sr => {
        const reliability = sr.totalProduced / (sr.totalProduced + sr.totalMissed);
        const weight = reliability / totalReliability;
        return {
          vote_address: sr.address,
          vote_count: Math.floor(votingPower * weight)
        };
      });
    }
  }

  // Get current votes
  async getCurrentVotes(address) {
    const response = await fetch(`${this.baseUrl}/wallet/getaccount`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ address, visible: true })
    });
    
    const account = await response.json();
    return account.votes || [];
  }

  // Estimate voting rewards
  async estimateRewards(voterAddress) {
    const votes = await this.getCurrentVotes(voterAddress);
    const witnesses = await this.getWitnesses();
    
    let estimatedDaily = 0;
    
    for (const vote of votes) {
      const sr = witnesses.find(w => w.address === vote.vote_address);
      if (sr && sr.brokerage) {
        // SR shares (100 - brokerage)% of rewards with voters
        const rewardShare = (100 - sr.brokerage) / 100;
        const srDailyReward = 16 * 20 * 60 * 24; // 16 TRX per block
        const voterShare = (vote.vote_count / sr.voteCount) * srDailyReward * rewardShare;
        estimatedDaily += voterShare;
      }
    }
    
    return {
      daily: estimatedDaily,
      monthly: estimatedDaily * 30,
      yearly: estimatedDaily * 365,
      apy: (estimatedDaily * 365 / (votes.reduce((sum, v) => sum + v.vote_count, 0) / 1000000)) * 100
    };
  }
}

// Example usage
async function manageVoting() {
  const strategy = new VotingStrategy('YOUR_API_KEY');
  
  // Check voting power
  const power = await strategy.getVotingPower('TVoterAddress...');
  console.log(`Available voting power: ${power} TRX`);
  
  // Optimize vote distribution
  const srList = ['TSR1...', 'TSR2...', 'TSR3...'];
  const optimizedVotes = await strategy.optimizeVotes(
    'TVoterAddress...',
    srList,
    'weighted'
  );
  
  console.log('Optimized vote distribution:', optimizedVotes);
  
  // Estimate rewards
  const rewards = await strategy.estimateRewards('TVoterAddress...');
  console.log(`Estimated APY: ${rewards.apy.toFixed(2)}%`);
}
```

## Best Practices

### 1. **Research Before Voting**

- Check SR reliability (>99.5% uptime)
- Review SR contributions to ecosystem
- Verify reward distribution policies

### 2. **Vote Management**

- Regularly review and update votes
- Monitor SR performance changes
- Rebalance votes based on performance

### 3. **Security**

- Use multi-signature for large voting accounts
- Verify SR addresses before voting
- Keep voting transactions records

### 4. **Optimization**

- Diversify votes across multiple reliable SRs
- Consider both rewards and network health
- Participate in governance discussions

## Common Errors

| Error                               | Description                | Solution                             |
| ----------------------------------- | -------------------------- | ------------------------------------ |
| `Insufficient frozen balance`       | Not enough voting power    | Freeze more TRX first                |
| `Invalid witness address`           | SR address not found       | Verify SR address from listwitnesses |
| `Total votes exceed frozen balance` | Votes > available power    | Reduce total vote count              |
| `Contract validate error`           | Invalid transaction format | Check parameter structure            |

## Use Cases

- **Governance Participation**: Vote for network validators
- **Reward Earning**: Earn passive income from voting
- **SR Support**: Support specific Super Representatives
- **Network Decentralization**: Distribute voting power
- **Strategic Voting**: Optimize rewards through vote management

## Related Methods

- [wallet/listwitnesses](https://www.dwellir.com/docs/tron/wallet-listwitnesses) - Get list of Super Representatives
- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Freeze TRX for voting power
- [wallet/getaccount](https://www.dwellir.com/docs/tron/wallet-getaccount) - Check current votes

---

## web3_clientVersion - TRON RPC Method

# web3_clientVersion - TRON RPC Method

Returns the current client software version string for your TRON node, including the client name, version number, OS, and runtime.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

## When to Use This Method

`web3_clientVersion` is valuable for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('TRON client:', clientVersion);

// Using fetch
const response = await fetch('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

client_version = w3.client_version
print(f'TRON client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("TRON client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/tron/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/tron/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/tron/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/tron/net_peerCount) - Get number of connected peers

---

## web3_sha3 - TRON RPC Method

# web3_sha3 - TRON RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on TRON.

> **Why TRON?** Build on the TVM-compatible Layer 1 for TRC-20 payments, wallet APIs, and low-cost smart contract execution with TVM compatibility paired with native TRON wallet APIs, DPoS block production, and low-cost transaction flows.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for TRON developers building payment rails, exchanges, and consumer crypto applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/jsonrpc'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/tron/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/tron/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/tron/web3_clientVersion) - Get node client version

---

## Unichain RPC Endpoint: Chain ID 130, HTTPS and WebSocket

# Unichain RPC Endpoint: Chain ID 130, HTTPS and WebSocket

## Unichain RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Unichain supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Unichain?

To get a Unichain mainnet endpoint, see [Unichain RPC endpoints](https://www.dwellir.com/networks/unichain).

Unichain is a fast, decentralized Superchain L2 built to be the home for DeFi and liquidity across chains. Developed by Uniswap on the OP Stack, Unichain addresses key challenges in the Ethereum ecosystem with innovative solutions for cost, speed, and MEV protection.

### **Ultra-Fast Execution**

- **1-Second Block Times** - Fast transaction confirmations
- **250ms Sub-blocks** - Coming soon for instant user experiences
- **200-250ms Finality** - Significantly faster than Ethereum's 12 seconds

### **Cost-Efficient DeFi**

- **95% Lower Costs** - Compared to Ethereum L1
- **MEV Protection** - Verifiable block building with TEE
- **No Failed Transaction Fees** - Trustless revert protection

### **Cross-Chain Native**

- **Superchain Interoperability** - Single-block cross-chain messaging
- **ERC-7683 Support** - Cross-Chain Intents standard
- **Unified Liquidity** - Seamless multi-chain DeFi

## Quick Start with Unichain

## Network Specifications

| Parameter  | Value     | Details      |
| ---------- | --------- | ------------ |
| Chain ID   | 130       | Mainnet      |
| Currency   | ETH       | Native Token |
| Block Time | 1s        | 250ms soon   |
| Finality   | 200-250ms | Ultra-fast   |

## Unique Features

### **MEV Protection**

Unichain employs a **Trusted Execution Environment (TEE)** for verifiable block building, ensuring:

- Transparent transaction ordering
- Protection against MEV extraction
- Fair and predictable execution

### **UNI Token Utility**

The UNI token powers Unichain's validation network:

- **Stake UNI** to become a validator
- **Earn 65%** of net chain revenue
- **Secure the network** through decentralized validation

### **Stage 1 Rollup**

Unichain launches as a Stage 1 rollup with:

- Permissionless fault proof system
- Independent transaction verification
- Enhanced security from day one

### **Native Uniswap Integration**

- **Uniswap v4 Hooks** - Native integration for advanced DeFi
- **Optimized for DEX** - Purpose-built for decentralized trading
- **Liquidity Hub** - Central point for cross-chain liquidity

## Available Methods

## Developer Resources

### Smart Contract Development

```solidity
// Deploy your DeFi protocols on Unichain
pragma solidity ^0.8.0;

contract MyDeFiProtocol {
    // Leverage Unichain's fast execution and MEV protection
    // Native support for Uniswap v4 hooks
}
```

### Web3 Integration

```javascript
// Connect to Unichain with Web3.js
const Web3 = require('web3');
const web3 = new Web3('https://api-unichain-mainnet.dwellir.com');

// Unichain Mainnet Chain ID: 130
const chainId = 130;

async function getBlockNumber() {
  const blockNumber = await web3.eth.getBlockNumber();
  console.log('Latest Unichain block:', blockNumber);
}
```

### Ethers.js Example

```javascript
// Using Ethers.js with Unichain
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider(
  'https://api-unichain-mainnet.dwellir.com'
);

// Check network
const network = await provider.getNetwork();
console.log('Connected to Unichain:', network.chainId === 130);
```

## Ecosystem & DApps

### **DeFi Protocols**

Leading DeFi applications already deployed on Unichain:

- **Uniswap** - Native DEX with v4 hooks
- **Morpho** - Lending protocol
- **Euler** - Permissionless lending
- **Lido** - Liquid staking
- **Renzo** - Liquid restaking

### **Bridge Solutions**

- **Native Superchain Bridge** - Direct bridging within Optimism ecosystem
- **Cross-Chain Intents** - ERC-7683 standard support
- **Unified Liquidity** - Seamless asset movement

### **Developer Tools**

- **Open Source** - MIT licensed codebase
- **OP Stack Compatible** - Familiar development environment
- **TEE Integration** - Advanced security features

## Network Information

### Mainnet (Chain ID: 130)

| Parameter    | Value                                                | Details |
| ------------ | ---------------------------------------------------- | ------- |
| RPC Endpoint | `https://api-unichain-mainnet.dwellir.com`           |         |
| WebSocket    | `wss://api-unichain-mainnet.dwellir.com`             |         |
| Explorer     | [Unichain Explorer](https://unichain.blockscout.com) |         |
| Status       | Live                                                 |         |

### Testnet (Chain ID: 1301)

| Parameter    | Value                                                                | Details |
| ------------ | -------------------------------------------------------------------- | ------- |
| Network      | Unichain Sepolia                                                     |         |
| RPC Endpoint | `https://api-unichain-sepolia.n.dwellir.com/YOUR_API_KEY`            |         |
| WebSocket    | `wss://api-unichain-sepolia.n.dwellir.com/YOUR_API_KEY`              |         |
| Explorer     | [Unichain Sepolia Explorer](https://unichain-sepolia.blockscout.com) |         |
| Faucet       | Available for testing                                                |         |

## API Methods

### Core Ethereum Methods

All standard Ethereum JSON-RPC methods are supported:

- Transaction Methods (`eth_sendTransaction`, `eth_getTransactionReceipt`)
- Block Methods (`eth_getBlockByNumber`, `eth_blockNumber`)
- Account Methods (`eth_getBalance`, `eth_getCode`)
- Event Methods (`eth_getLogs`, `eth_newFilter`)

### Unichain L2 Specific

Enhanced methods for L2 operations:

- `eth_estimateL1Fee` - Estimate L1 fee component
- `rollup_gasPrices` - Get current L2 gas prices
- `rollup_getInfo` - Get rollup configuration

### Debug & Trace Methods

Advanced debugging capabilities:

- `debug_traceTransaction` - Detailed transaction traces
- `debug_traceBlockByNumber` - Block-level debugging
- `debug_traceCall` - Simulate and trace calls

## Best Practices

### 1. **Leverage Sub-blocks**

Take advantage of Unichain's upcoming 250ms sub-blocks for instant UX:

```javascript
// Monitor sub-blocks for real-time updates
provider.on('block', (blockNumber) => {
  // React to new blocks in near real-time
});
```

### 2. **MEV Protection**

Build with confidence knowing transactions are protected:

```javascript
// Transactions are protected from sandwich attacks
// and other MEV extraction techniques
const tx = await contract.swap(tokenA, tokenB, amount);
```

### 3. **Cross-Chain Design**

Design for interoperability from the start:

```javascript
// Leverage native cross-chain messaging
const crossChainTx = await bridge.sendMessage(
  targetChain,
  message
);
```

## Migration Guide

### From Ethereum Mainnet

1. Update chain ID to 130
2. Point RPC to Unichain endpoint
3. Enjoy 95% cost reduction

### From Other L2s

1. Minimal code changes required
2. Standard Ethereum tooling works
3. Enhanced features available

## Resources & Support

### Developer Resources

- **Official Docs**: [Unichain documentation](https://docs.unichain.org)
- **GitHub**: Open source codebase (MIT license)
- **Explorer**: [Unichain Explorer](https://unichain.blockscout.com)

### Need Help?

- **Email**: <support@dwellir.com>
- **Documentation**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Best Unichain RPC Providers for 2026](https://www.dwellir.com/blog/best-unichain-rpc-providers)

***

*Start building on Unichain with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Unichain RPC Method

# debug_traceBlock - Unichain RPC Method

Traces all transactions in a block on Unichain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Unichain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Unichain
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Unichain:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Unichain blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/unichain/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/unichain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/unichain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/unichain/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Unichain RPC Method

# debug_traceBlockByHash - Unichain RPC Method

Traces all transactions in a block on Unichain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Unichain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Unichain
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Unichain:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Unichain:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/unichain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/unichain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/unichain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/unichain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/unichain/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Unichain RPC Method

# debug_traceBlockByNumber - Unichain RPC Method

Traces all transactions in a block on Unichain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Unichain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Unichain execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Unichain:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Unichain:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/unichain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/unichain/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/unichain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/unichain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Unichain RPC Method

# debug_traceCall - Unichain RPC Method

Traces a call on Unichain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Unichain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Unichain
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Unichain to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Unichain:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Unichain:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/unichain/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/unichain/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/unichain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/unichain/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Unichain RPC Method

# debug_traceTransaction - Unichain RPC Method

Traces a transaction execution on Unichain by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Unichain
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/unichain/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/unichain/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Unichain RPC Method

# eth_accounts - Unichain RPC Method

Returns a list of addresses owned by the client on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/unichain/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/unichain/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Unichain RPC Method

# eth_blockNumber - Unichain RPC Method

Returns the number of the most recent block on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_blockNumber` is fundamental for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Syncing Applications** - Keep your dApp in sync with the latest Unichain blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Unichain block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Unichain block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Unichain block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Unichain block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Unichain block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Unichain:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Unichain:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Unichain node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/unichain/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/unichain/eth_syncing) - Check if node is still syncing

---

## eth_call - Unichain RPC Method

# eth_call - Unichain RPC Method

Executes a new message call immediately without creating a transaction on Unichain. Used for reading smart contract state.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

The `eth_call` method serves these key scenarios for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Unichain
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Unichain. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Unichain
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Unichain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Unichain RPC Method

# eth_chainId - Unichain RPC Method

Returns the chain ID used for transaction signing on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_chainId` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/unichain/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/unichain/eth_syncing) - Check sync status

---

## eth_coinbase - Unichain RPC Method

# eth_coinbase - Unichain RPC Method

Checks the legacy `eth_coinbase` compatibility method on Unichain. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Unichain coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Unichain coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Unichain coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Unichain coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Unichain coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Unichain nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/unichain/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/unichain/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/unichain/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Unichain RPC Method

# eth_estimateGas - Unichain RPC Method

Estimates the gas necessary to execute a transaction on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Unichain
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Unichain.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Unichain may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/unichain/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 data postin...

# eth_estimateL1Fee - Estimate L1 data postin...

Estimate L1 data posting fee on the Unichain network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateL1Fee",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_estimateL1Fee',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_feeHistory - Unichain RPC Method

# eth_feeHistory - Unichain RPC Method

Returns historical gas fee data on Unichain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Unichain without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Unichain.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Unichain) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/unichain/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/unichain/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Unichain RPC Method

# eth_gasPrice - Unichain RPC Method

Returns the current gas price on Unichain in wei.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Unichain
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Unichain. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Unichain, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Unichain: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Unichain supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/unichain/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/unichain/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Unichain RPC Method

# eth_getBalance - Unichain RPC Method

Returns the balance of a given address on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getBalance` is fundamental for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Unichain
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Unichain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Unichain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Unichain`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Unichain at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Unichain')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Unichain')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Unichain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/unichain/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/unichain/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Unichain RPC Method

# eth_getBlockByHash - Unichain RPC Method

Returns information about a block by hash on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getBlockByHash` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Unichain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Unichain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Unichain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/unichain/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Unichain RPC Method

# eth_getBlockByNumber - Unichain RPC Method

Returns information about a block by block number on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getBlockByNumber` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Unichain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Unichain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Unichain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/unichain/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/unichain/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/unichain/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Unichain RPC Method

# eth_getBlockReceipts - Unichain RPC Method

Returns all transaction receipts for a block on Unichain. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getBlockReceipts` is useful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Unichain, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Unichain. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x480c43fe03129d5842659d3456eb1ca895e77a2f607de2195ad4b2ee02743e06",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/unichain/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/unichain/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Unichain RPC Method

# eth_getCode - Unichain RPC Method

Returns the bytecode at a given address on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getCode` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Unichain
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Unichain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Unichain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/unichain/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/unichain/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Unichain RPC Method

# eth_getFilterChanges - Unichain RPC Method

Polls a filter on Unichain for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getFilterChanges` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Unichain
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Unichain:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/unichain/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/unichain/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/unichain/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/unichain/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/unichain/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Unichain RPC Method

# eth_getFilterLogs - Unichain RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Unichain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getFilterLogs` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Unichain
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/unichain/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/unichain/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/unichain/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/unichain/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Unichain RPC Method

# eth_getLogs - Unichain RPC Method

Returns an array of all logs matching a given filter object on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Unichain for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Unichain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Unichain.

```javascript
const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Unichain enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Unichain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/unichain/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/unichain/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Unichain RPC Method

# eth_getStorageAt - Unichain RPC Method

Returns the value from a storage position at a given address on Unichain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getStorageAt` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **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 exchanges, liquidity protocols, and MEV-protected DeFi applications
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-unichain-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 = '0x4200000000000000000000000000000000000006'
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-unichain-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-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 Unichain:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-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-unichain-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 = '0x4200000000000000000000000000000000000006';
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 Unichain:`);
  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/unichain/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/unichain/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/unichain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Unichain RPC Method

# eth_getTransactionByHash - Unichain RPC Method

Returns the information about a transaction by transaction hash on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getTransactionByHash` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Unichain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Unichain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Unichain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/unichain/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Unichain RPC Method

# eth_getTransactionCount - Unichain RPC Method

Returns the number of transactions sent from an address on Unichain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getTransactionCount` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Unichain
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Unichain nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'Unichain nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Unichain nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Unichain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/unichain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/unichain/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/unichain/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Unichain RPC Method

# eth_getTransactionReceipt - Unichain RPC Method

Returns the receipt of a transaction by transaction hash on Unichain. Receipt is only available for mined transactions.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_getTransactionReceipt` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Unichain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Unichain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Unichain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x9706ecd214808103184e8c0f79eefebe1cb5e87539cbe81ec191426af62c97ec")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/unichain/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/unichain/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Unichain RPC Method

# eth_hashrate - Unichain RPC Method

Returns the legacy `eth_hashrate` compatibility value on Unichain. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Unichain hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Unichain hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Unichain hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Unichain hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Unichain hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/unichain/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/unichain/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/unichain/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Unichain RPC Method

# eth_maxPriorityFeePerGas - Unichain RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Unichain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Unichain
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Unichain priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Unichain priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Unichain priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Unichain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Unichain:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/unichain/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/unichain/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/unichain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Unichain RPC Method

# eth_mining - Unichain RPC Method

Checks the legacy `eth_mining` compatibility method on Unichain. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Unichain mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Unichain mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Unichain mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Unichain mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Unichain mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/unichain/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/unichain/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/unichain/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Unichain RPC Method

# eth_newBlockFilter - Unichain RPC Method

Creates a filter on Unichain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_newBlockFilter` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Block Monitoring** - Detect new blocks on Unichain as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Unichain:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/unichain/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/unichain/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/unichain/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/unichain/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Unichain RPC Method

# eth_newFilter - Unichain RPC Method

Creates a filter object on Unichain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_newFilter` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Event Monitoring** - Subscribe to specific contract events on Unichain such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Unichain:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/unichain/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/unichain/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/unichain/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/unichain/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/unichain/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Unichain RPC Method

# eth_newPendingTransactionFilter - Unichain RPC Method

Creates a filter on Unichain that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Mempool Monitoring** - Observe unconfirmed transactions on Unichain to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for decentralized exchanges, liquidity protocols, and MEV-protected DeFi applications

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Unichain...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Unichain:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/unichain/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/unichain/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/unichain/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Unichain RPC Method

# eth_protocolVersion - Unichain RPC Method

Returns the current Ethereum protocol version used by the Unichain node.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_protocolVersion` is useful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Unichain protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Unichain protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Unichain protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Unichain protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Unichain protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Unichain nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/unichain/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/unichain/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/unichain/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Unichain RPC Method

# eth_sendRawTransaction - Unichain RPC Method

Submits a pre-signed transaction for broadcast to Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Unichain
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Unichain mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/unichain/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/unichain/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/unichain/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Unichain RPC Method

# eth_sendTransaction - Unichain RPC Method

Creates and sends a new transaction from an unlocked account on Unichain. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Unichain tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Unichain tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Unichain tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Unichain tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Unichain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Unichain dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/unichain/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/unichain/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Unichain RPC Method

# eth_signTransaction - Unichain RPC Method

Signs a transaction with the private key of the specified account on Unichain without submitting it to the network.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Unichain tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Unichain tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Unichain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Unichain:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/unichain/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/unichain/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/unichain/eth_accounts) - List accounts available for signing

---

## eth_syncing - Unichain RPC Method

# eth_syncing - Unichain RPC Method

Returns the sync status of your Unichain node - either `false` when fully synced, or an object describing the sync progress.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_syncing` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Unichain node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Unichain node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Unichain node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/unichain/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/unichain/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/unichain/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/unichain/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Unichain RPC Method

# eth_uninstallFilter - Unichain RPC Method

Removes a filter on Unichain that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`eth_uninstallFilter` is important for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/unichain/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/unichain/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/unichain/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/unichain/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/unichain/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Unichain RPC Method

# net_listening - Unichain RPC Method

Checks whether the connected Unichain client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`net_listening` is useful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Unichain node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Unichain node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Unichain node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/unichain/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/unichain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/unichain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/unichain/web3_clientVersion) - Get node client info

---

## net_peerCount - Unichain RPC Method

# net_peerCount - Unichain RPC Method

Returns the number of peers currently connected to your Unichain node.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`net_peerCount` is important for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Unichain deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Unichain peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Unichain peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Unichain peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Unichain nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/unichain/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/unichain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/unichain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/unichain/web3_clientVersion) - Get node client info

---

## net_version - Unichain RPC Method

# net_version - Unichain RPC Method

Returns the current network ID on Unichain as a decimal string. The network ID identifies which network the node is connected to.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`net_version` is essential for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Endpoint Identification** - Confirm your application is connected to the expected Unichain network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Unichain network ID:', networkId);

// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Unichain network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Unichain network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/unichain/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/unichain/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/unichain/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/unichain/eth_syncing) - Check node sync progress

---

## optimism_rollupConfig - Get rollup configur...

# optimism_rollupConfig - Get rollup configur...

Get the rollup configuration parameters on the Unichain network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "optimism_rollupConfig",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Object containing rollup configuration details including genesis information, block time, sequencer drift, chain IDs, and other rollup parameters.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "genesis": {
      "l1": {
        "hash": "0x...",
        "number": 12345
      },
      "l2": {
        "hash": "0x...",
        "number": 0
      },
      "l2_time": 1234567890,
      "system_config": {
        "batcherAddr": "0x...",
        "overhead": "0x...",
        "scalar": "0x...",
        "gasLimit": 30000000
      }
    },
    "block_time": 2,
    "max_sequencer_drift": 600,
    "seq_window_size": 3600,
    "channel_timeout": 300,
    "l1_chain_id": 1,
    "l2_chain_id": 130,
    "regolith_time": 0,
    "canyon_time": 0,
    "batch_inbox_address": "0x...",
    "deposit_contract_address": "0x...",
    "l1_system_config_address": "0x...",
    "protocol_versions_address": "0x..."
  }
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "optimism_rollupConfig",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'optimism_rollupConfig',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## rollup_gasPrices - Get L2 gas price oracle...

# rollup_gasPrices - Get L2 gas price oracle...

Returns the L2 gas-price oracle data that Unichain uses to compute total fees. The payload mirrors Optimism Bedrock networks and includes:

- `gasPrice` — Total gas price Unichain applies to transactions.
- `l1GasPrice` — Current L1 gas price component applied to calldata.
- `l2GasPrice` — The execution gas component on Unichain itself.
- `baseFeeScalar`, `blobBaseFeeScalar`, `overhead` — Scalars used by the sequencer when combining L1/L2 costs.

Use this method when you must break down L1 calldata charges, size cross-chain deposits, or monitor Unichain fee dynamics beyond what `eth_gasPrice` exposes.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): An object describing the current Unichain gas oracle state. Each field is returned as a hexadecimal string representing wei.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "gasPrice": "0x9184e72a000",
    "l1GasPrice": "0x4a817c800",
    "l2GasPrice": "0x9184e72a",
    "baseFeeScalar": "0x1f4",
    "blobBaseFeeScalar": "0x0",
    "overhead": "0xaae60"
  }
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_gasPrices",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_gasPrices',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## rpc_modules - Unichain RPC Method

# rpc_modules - Unichain RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Unichain endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`rpc_modules` is useful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/unichain/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/unichain/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Unichain RPC Method

# web3_clientVersion - Unichain RPC Method

Returns the current client software version string for your Unichain node, including the client name, version number, OS, and runtime.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

## When to Use This Method

`web3_clientVersion` is valuable for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Unichain client:', clientVersion);

// Using fetch
const response = await fetch('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Unichain client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Unichain client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/unichain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/unichain/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/unichain/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/unichain/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Unichain RPC Method

# web3_sha3 - Unichain RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Unichain.

> **Why Unichain?** Build on Uniswap's DeFi-optimized Superchain L2 with 250ms sub-blocks and 95% lower costs than Ethereum with 250ms sub-blocks (fastest L2), TEE-secured block building, native Superchain interoperability, and 65% revenue to validators.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for DeFi developers, liquidity protocol builders, and teams building on the Optimism Superchain:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/unichain/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/unichain/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/unichain/web3_clientVersion) - Get node client version

---

## Viction - EVM-Compatible Blockchain Documentation

# Viction - EVM-Compatible Blockchain Documentation

## Viction RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Viction supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Viction?

Viction is a people-centric blockchain designed to make Web3 accessible and secure for all users. Built with an innovative Proof-of-Stake Voting (PoSV) consensus mechanism, Viction offers:

### **Lightning Fast Performance**

- **2-second block times** - Get near-instant transaction confirmations
- **2000+ TPS capacity** - Handle high-volume applications efficiently
- **Zero gas fees** - Remove cost barriers for frequent transactions

### **Enterprise Security**

- **150 Masternode network** - Decentralized validation with PoSV consensus
- **Double validation** - Enhanced security through dual-node verification
- **Battle-tested** - In production since 2018 with proven reliability

### **Developer-Friendly Ecosystem**

- **Full EVM compatibility** - Deploy Ethereum smart contracts seamlessly
- **World Wide Chain** - Innovative app chain framework for scalability
- **Rich tooling support** - Works with Hardhat, Foundry, Remix, and more

## Quick Start with Viction

Connect to Viction in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Viction mainnet
const provider = new JsonRpcProvider(
  'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0xB786D9c8120D311b948cF1e5Aa48D8fBacf477E2');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Viction mainnet
const web3 = new Web3(
  'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Viction:', chainId === 88);

// Get gas price (often zero on Viction)
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http, defineChain } from 'viem';

// Define Viction chain
const viction = defineChain({
  id: 88,
  name: 'Viction',
  network: 'viction',
  nativeCurrency: {
    decimals: 18,
    name: 'Viction',
    symbol: 'VIC',
  },
  rpcUrls: {
    default: {
      http: ['https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'],
    },
  },
  blockExplorers: {
    default: { name: 'VicScan', url: 'https://vicscan.xyz' },
  },
});

// Create Viction client
const client = createPublicClient({
  chain: viction,
  transport: http('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0xB786D9c8120D311b948cF1e5Aa48D8fBacf477E2',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x1a597B5b3057393dD46bdA8A0d8AF35468Bf53c1'],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 88        | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | VIC       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Viction supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with zero gas fees for most transactions.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Viction transactions typically confirm in 2-4 seconds
  console.log('Transaction confirmed in block:', receipt.blockNumber);

  return receipt;
}
```

### Zero Gas Optimization

Take advantage of Viction's zero gas fee structure:

```javascript
// Most transactions on Viction have zero gas cost
const gasPrice = await provider.getGasPrice();
console.log('Gas price:', gasPrice.toString()); // Often "0"

// Still estimate gas for contract interactions
const gasLimit = await provider.estimateGas(tx);

const transaction = {
  to: recipient,
  value: amount,
  gasPrice: gasPrice,
  gasLimit: gasLimit
};
```

### Event Filtering

Efficiently query contract events with fast block times:

```javascript
// Query events with Viction's fast block confirmation
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 1000; // Viction recommended batch size

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class VictionProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for transaction"

Ensure you have enough VIC for transaction execution:

```javascript
// Check VIC balance
const balance = await provider.getBalance(address);
const gasLimit = await provider.estimateGas(tx);
const totalRequired = gasLimit + tx.value;

if (balance < totalRequired) {
  throw new Error(`Need ${totalRequired - balance} more VIC`);
}
```

### Error: "Transaction underpriced"

While Viction often has zero gas fees, some operations may require minimal gas:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  gasPrice: feeData.gasPrice || 0,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from Ethereum to Viction requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Viction)
const provider = new JsonRpcProvider(
  'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically
// Same tooling and libraries
// Note: Different chain ID (88)
// Note: Separate block numbers
// Note: Zero gas fees for most transactions
```

## Resources & Tools

### Official Resources

- [Viction Documentation](https://docs.viction.xyz)
- [VicScan Block Explorer](https://vicscan.xyz)
- [VicMaster Staking Platform](https://vicmaster.xyz)

### Developer Tools

- [Developer Guide](https://docs.viction.xyz/developer-guide)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on Viction with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Viction RPC Method

# debug_traceBlock - Viction RPC Method

Traces all transactions in a block on Viction by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Viction - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Viction
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Viction:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Viction blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/viction/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/viction/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/viction/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/viction/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Viction RPC Method

# debug_traceBlockByHash - Viction RPC Method

Traces all transactions in a block on Viction identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Viction - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Viction
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Viction:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Viction:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/viction/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/viction/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/viction/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/viction/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/viction/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Viction RPC Method

# debug_traceBlockByNumber - Viction RPC Method

Traces all transactions in a block on Viction identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Viction - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Viction execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Viction:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Viction:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/viction/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/viction/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/viction/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/viction/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Viction RPC Method

# debug_traceCall - Viction RPC Method

Traces a call on Viction without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Viction - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Viction
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "data": "0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
        "data": "0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
        "data": "0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    data: '0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    data: '0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    'data': '0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
        "data": "0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Viction to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Viction:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Viction:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/viction/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/viction/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/viction/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/viction/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Viction RPC Method

# debug_traceTransaction - Viction RPC Method

Traces a transaction execution on Viction by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Viction
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/viction/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/viction/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Viction RPC Method

# eth_accounts - Viction RPC Method

Returns a list of addresses owned by the client on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/viction/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/viction/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Viction RPC Method

# eth_blockNumber - Viction RPC Method

Returns the number of the most recent block on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_blockNumber` is fundamental for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Syncing Applications** - Keep your dApp in sync with the latest Viction blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Viction block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Viction block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Viction block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Viction block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Viction block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Viction:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Viction:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Viction node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/viction/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/viction/eth_syncing) - Check if node is still syncing

---

## eth_call - Viction RPC Method

# eth_call - Viction RPC Method

Executes a new message call immediately without creating a transaction on Viction. Used for reading smart contract state.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

The `eth_call` method serves these key scenarios for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Viction
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on gasless token operations, consumer-friendly dApps, and cost-free user onboarding

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';
const walletAddress = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Viction. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Viction
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Viction

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "data": "0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "data": "0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    data := common.FromHex("0x70a08231000000000000000000000000C054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Viction RPC Method

# eth_chainId - Viction RPC Method

Returns the chain ID used for transaction signing on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_chainId` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on gasless token operations, consumer-friendly dApps, and cost-free user onboarding

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/viction/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/viction/eth_syncing) - Check sync status

---

## eth_coinbase - Viction RPC Method

# eth_coinbase - Viction RPC Method

Checks the legacy `eth_coinbase` compatibility method on Viction. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Viction coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Viction coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Viction coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Viction coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Viction coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Viction nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/viction/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/viction/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/viction/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Viction RPC Method

# eth_estimateGas - Viction RPC Method

Estimates the gas necessary to execute a transaction on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Viction
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Viction.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Viction may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "to": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/viction/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Viction RPC Method

# eth_feeHistory - Viction RPC Method

Returns historical gas fee data on Viction, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Viction without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Viction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Viction) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/viction/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/viction/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Viction RPC Method

# eth_gasPrice - Viction RPC Method

Returns the current gas price on Viction in wei.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Viction
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Viction. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Viction, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Viction: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Viction supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/viction/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/viction/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Viction RPC Method

# eth_getBalance - Viction RPC Method

Returns the balance of a given address on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getBalance` is fundamental for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Viction
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Viction
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Viction. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Viction`);
  return balance;
}

displayBalance('0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Viction at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Viction')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Viction')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Viction.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/viction/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/viction/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Viction RPC Method

# eth_getBlockByHash - Viction RPC Method

Returns information about a block by hash on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getBlockByHash` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Viction
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Viction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Viction.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/viction/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Viction RPC Method

# eth_getBlockByNumber - Viction RPC Method

Returns information about a block by block number on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getBlockByNumber` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Viction
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Viction with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Viction. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/viction/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/viction/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/viction/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Viction RPC Method

# eth_getBlockReceipts - Viction RPC Method

Returns all transaction receipts for a block on Viction. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getBlockReceipts` is useful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Viction, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Viction. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xdc0f40042f5b5b45232a3695800ec85ecb9227f3a4323068d2a0f59414a55dab",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/viction/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/viction/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Viction RPC Method

# eth_getCode - Viction RPC Method

Returns the bytecode at a given address on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getCode` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Viction
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on gasless token operations, consumer-friendly dApps, and cost-free user onboarding

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Viction:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Viction:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/viction/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/viction/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Viction RPC Method

# eth_getFilterChanges - Viction RPC Method

Polls a filter on Viction for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getFilterChanges` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Viction
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Viction:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/viction/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/viction/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/viction/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/viction/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/viction/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Viction RPC Method

# eth_getFilterLogs - Viction RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Viction. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getFilterLogs` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Viction
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/viction/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/viction/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/viction/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/viction/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Viction RPC Method

# eth_getLogs - Viction RPC Method

Returns an array of all logs matching a given filter object on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Viction for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Viction
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Viction.

```javascript
const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Viction enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Viction, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/viction/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/viction/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Viction RPC Method

# eth_getStorageAt - Viction RPC Method

Returns the value from a storage position at a given address on Viction. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getStorageAt` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **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 gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **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": [
    "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "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-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce', '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-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';

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-viction-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 = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
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-viction-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-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    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 Viction:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-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-viction-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 = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';
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 Viction:`);
  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/viction/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/viction/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/viction/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Viction RPC Method

# eth_getTransactionByHash - Viction RPC Method

Returns the information about a transaction by transaction hash on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getTransactionByHash` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Viction
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Viction. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Viction. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/viction/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Viction RPC Method

# eth_getTransactionCount - Viction RPC Method

Returns the number of transactions sent from an address on Viction, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getTransactionCount` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Viction
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Viction nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce'
nonce = get_transaction_count(address)
print(f'Viction nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Viction nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Viction:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/viction/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/viction/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/viction/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Viction RPC Method

# eth_getTransactionReceipt - Viction RPC Method

Returns the receipt of a transaction by transaction hash on Viction. Receipt is only available for mined transactions.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_getTransactionReceipt` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Viction and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Viction. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Viction, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x2d7d9448138fea121bb3ae84ee69442ead61605462cc260b04d0e450782d9786")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/viction/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/viction/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Viction RPC Method

# eth_hashrate - Viction RPC Method

Returns the legacy `eth_hashrate` compatibility value on Viction. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Viction hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Viction hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Viction hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Viction hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Viction hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/viction/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/viction/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/viction/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Viction RPC Method

# eth_maxPriorityFeePerGas - Viction RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Viction. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Viction
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Viction priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Viction priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Viction priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Viction:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Viction:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/viction/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/viction/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/viction/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Viction RPC Method

# eth_mining - Viction RPC Method

Checks the legacy `eth_mining` compatibility method on Viction. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Viction mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Viction mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Viction mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Viction mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Viction mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/viction/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/viction/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/viction/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Viction RPC Method

# eth_newBlockFilter - Viction RPC Method

Creates a filter on Viction that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_newBlockFilter` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Block Monitoring** - Detect new blocks on Viction as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Viction:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/viction/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/viction/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/viction/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/viction/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Viction RPC Method

# eth_newFilter - Viction RPC Method

Creates a filter object on Viction based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_newFilter` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Event Monitoring** - Subscribe to specific contract events on Viction such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to gasless token operations, consumer-friendly dApps, and cost-free user onboarding
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Viction:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/viction/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/viction/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/viction/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/viction/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/viction/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Viction RPC Method

# eth_newPendingTransactionFilter - Viction RPC Method

Creates a filter on Viction that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Mempool Monitoring** - Observe unconfirmed transactions on Viction to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for gasless token operations, consumer-friendly dApps, and cost-free user onboarding

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Viction...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Viction:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/viction/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/viction/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/viction/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Viction RPC Method

# eth_protocolVersion - Viction RPC Method

Returns the current Ethereum protocol version used by the Viction node.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_protocolVersion` is useful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Viction protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Viction protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Viction protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Viction protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Viction protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Viction nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/viction/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/viction/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/viction/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Viction RPC Method

# eth_sendRawTransaction - Viction RPC Method

Submits a pre-signed transaction for broadcast to Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Viction
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Viction mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/viction/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0xC054751BdBD24Ae713BA3Dc9Bd9434aBe2abc1ce")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/viction/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/viction/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Viction RPC Method

# eth_sendTransaction - Viction RPC Method

Creates and sends a new transaction from an unlocked account on Viction. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Viction tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Viction tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Viction tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Viction tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Viction tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Viction dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/viction/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/viction/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Viction RPC Method

# eth_signTransaction - Viction RPC Method

Signs a transaction with the private key of the specified account on Viction without submitting it to the network.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Viction tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Viction tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Viction tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Viction:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/viction/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/viction/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/viction/eth_accounts) - List accounts available for signing

---

## eth_syncing - Viction RPC Method

# eth_syncing - Viction RPC Method

Returns the sync status of your Viction node - either `false` when fully synced, or an object describing the sync progress.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_syncing` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Viction node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Viction node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Viction node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/viction/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/viction/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/viction/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/viction/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Viction RPC Method

# eth_uninstallFilter - Viction RPC Method

Removes a filter on Viction that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`eth_uninstallFilter` is important for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/viction/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/viction/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/viction/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/viction/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/viction/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Viction RPC Method

# net_listening - Viction RPC Method

Checks whether the connected Viction client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`net_listening` is useful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Viction node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Viction node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Viction node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/viction/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/viction/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/viction/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/viction/web3_clientVersion) - Get node client info

---

## net_peerCount - Viction RPC Method

# net_peerCount - Viction RPC Method

Returns the number of peers currently connected to your Viction node.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`net_peerCount` is important for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Viction deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Viction peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Viction peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Viction peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Viction nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/viction/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/viction/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/viction/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/viction/web3_clientVersion) - Get node client info

---

## net_version - Viction RPC Method

# net_version - Viction RPC Method

Returns the current network ID on Viction as a decimal string. The network ID identifies which network the node is connected to.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`net_version` is essential for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Endpoint Identification** - Confirm your application is connected to the expected Viction network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Viction network ID:', networkId);

// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Viction network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Viction network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/viction/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/viction/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/viction/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/viction/eth_syncing) - Check node sync progress

---

## rpc_modules - Viction RPC Method

# rpc_modules - Viction RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Viction endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`rpc_modules` is useful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/viction/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/viction/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Viction RPC Method

# web3_clientVersion - Viction RPC Method

Returns the current client software version string for your Viction node, including the client name, version number, OS, and runtime.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

## When to Use This Method

`web3_clientVersion` is valuable for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Viction client:', clientVersion);

// Using fetch
const response = await fetch('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Viction client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Viction client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/viction/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/viction/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/viction/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/viction/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Viction RPC Method

# web3_sha3 - Viction RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Viction.

> **Why Viction?** Build on the zero-gas L1 blockchain making Web3 accessible with 150 masternodes and VRC25 gasless tokens with zero-gas transactions via TomoZ, VRC25 gasless token standard, 150 masternodes, and partnerships with LayerZero and MoonPay.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for consumer dApp developers, teams requiring gasless UX, and builders targeting mainstream adoption:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-viction-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/viction/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/viction/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/viction/web3_clientVersion) - Get node client version

---

## World Chain RPC with Dwellir

# World Chain RPC with Dwellir

## World Chain RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where World Chain supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on World Chain?

World Chain is an Ethereum L2 built on the OP Stack that prioritizes verified humans over bots. Through World ID integration, verified users receive free gas allowances and priority blockspace:

### **Human-First Design**

- **Priority mempool** - Verified World ID holders get preferential block inclusion
- **Free gas allowances** - Recurring gas grants for verified humans
- **Sybil resistance** - Built-in protection against bot spam and attacks

### **Optimism Superchain**

- **OP Stack powered** - Built on battle-tested Optimism technology
- **Ethereum security** - Settles to mainnet for maximum security
- **EVM compatible** - Deploy existing Solidity contracts without changes

### **World Ecosystem**

- **World App integration** - Seamless access via the World super-app
- **World ID verification** - Privacy-preserving identity proof
- **Growing ecosystem** - Part of the broader World Network

## Quick Start with World Chain

Connect to World Chain in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem
Web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to World Chain mainnet
const provider = new JsonRpcProvider(
  'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to World Chain mainnet
const web3 = new Web3(
  'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to World Chain:', chainId === 480);

// Get gas price for transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http, defineChain } from 'viem';

// Define World Chain
const worldChain = defineChain({
  id: 480,
  name: 'World Chain',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'] },
  },
  blockExplorers: {
    default: { name: 'Worldscan', url: 'https://worldscan.org' },
  },
});

// Create World Chain client
const client = createPublicClient({
  chain: worldChain,
  transport: http('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read contract data
const data = await client.readContract({
  address: '0x...',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x...'],
});
```

```python
from web3 import Web3

# Connect to World Chain mainnet
web3 = Web3(Web3.HTTPProvider(
  'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection
print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # Should be 480

# Get latest block
latest_block = web3.eth.get_block('latest')
print(f'Latest block: {latest_block.number}')
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 480       | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | ETH       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

World Chain supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) as an OP Stack L2.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions efficiently:

```javascript
// Watch for transaction confirmation
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // Check transaction status
  if (receipt.status === 1) {
    console.log('Transaction successful');
  } else {
    console.log('Transaction failed');
  }

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on World Chain:

```javascript
// Get current fee data (EIP-1559)
const feeData = await provider.getFeeData();

// Estimate gas for transaction
const gasEstimate = await provider.estimateGas(tx);

// Calculate total cost
const totalCost = gasEstimate * feeData.gasPrice;
console.log('Estimated cost:', totalCost);
```

### Event Filtering

Efficiently query contract events with proper pagination:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 2000; // Recommended batch size
  const latestBlock = await provider.getBlockNumber();

  for (let i = fromBlock; i <= latestBlock; i += batchSize) {
    const toBlock = Math.min(i + batchSize - 1, latestBlock);
    const batch = await contract.queryFilter(filter, i, toBlock);
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class WorldChainProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds for gas"

World Chain transactions require ETH for gas fees:

```javascript
// Always account for gas in balance checks
const balance = await provider.getBalance(address);
const gasPrice = await provider.getGasPrice();
const gasLimit = await provider.estimateGas(tx);
const gasCost = gasPrice * gasLimit;

if (balance < (tx.value + gasCost)) {
  throw new Error(`Need ${(tx.value + gasCost) - balance} more wei`);
}
```

### Error: "Transaction underpriced"

Use current market gas prices:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Smoke Tests

### Test Connection with cURL

```bash
# Test World Chain mainnet
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
```

### Test with Ethers.js

```javascript
// Test mainnet connection
const mainnetProvider = new JsonRpcProvider(
  'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
);

const blockNumber = await mainnetProvider.getBlockNumber();
const network = await mainnetProvider.getNetwork();

console.log('Block number:', blockNumber);
console.log('Chain ID:', network.chainId); // Should be 480n
```

### Test with Web3.py

```python
from web3 import Web3

# Test connection
web3 = Web3(Web3.HTTPProvider(
  'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
))

print('Connected:', web3.is_connected())
print('Chain ID:', web3.eth.chain_id)  # Should be 480
print('Block number:', web3.eth.block_number)
```

## Migration Guide

### Migrating to Dwellir

Replace your existing RPC endpoint with Dwellir:

```javascript
// Before
const provider = new JsonRpcProvider('https://other-provider.com');

// After
const provider = new JsonRpcProvider(
  'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// All existing code works identically
// Same JSON-RPC methods supported
// Same response formats
// Note: Update your API endpoint URL
// Note: Add your Dwellir API key
```

## Resources & Tools

### Official Resources

- [World Chain Documentation](https://docs.world.org/world-chain)
- [World Chain Website](https://world.org/world-chain)
- [Worldscan Block Explorer](https://worldscan.org)

### Developer Tools

- [World Chain Bridge](https://worldchain-mainnet.bridge.alchemy.com)
- [World Chain Testnet Faucet](https://faucets.chain.link/worldchain-testnet)
- [L2Beat World Chain](https://l2beat.com/scaling/projects/world)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

### Related Reading

- [Top 7 World Chain RPC Providers](https://www.dwellir.com/blog/best-worldchain-rpc-providers)

***

*Start building on World Chain with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - World Chain RPC Method

# debug_traceBlock - World Chain RPC Method

Traces all transactions in a block on World Chain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for World Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for World Chain developers building sybil-resistant applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on World Chain
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for human-verified DeFi, identity-gated applications, bot-resistant services
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on World Chain:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in World Chain blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/world-chain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/world-chain/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - World Chain RPC Method

# debug_traceBlockByHash - World Chain RPC Method

Traces all transactions in a block on World Chain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for World Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for World Chain developers building sybil-resistant applications:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on World Chain
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for human-verified DeFi, identity-gated applications, bot-resistant services
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on World Chain:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on World Chain:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/world-chain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/world-chain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/world-chain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/world-chain/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - World Chain RPC Method

# debug_traceBlockByNumber - World Chain RPC Method

Traces all transactions in a block on World Chain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for World Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for World Chain developers building sybil-resistant applications:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of World Chain execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for human-verified DeFi, identity-gated applications, bot-resistant services
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on World Chain:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on World Chain:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/world-chain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/world-chain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/world-chain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - World Chain RPC Method

# debug_traceCall - World Chain RPC Method

Traces a call on World Chain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for World Chain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for World Chain developers building sybil-resistant applications:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on World Chain
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for human-verified DeFi, identity-gated applications, bot-resistant services
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on World Chain to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on World Chain:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on World Chain:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/world-chain/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/world-chain/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - World Chain RPC Method

# debug_traceTransaction - World Chain RPC Method

Traces a transaction execution on World Chain by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for human-verified DeFi, identity-gated applications, bot-resistant services
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on World Chain
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/world-chain/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/world-chain/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - World Chain RPC Method

# eth_accounts - World Chain RPC Method

Returns a list of addresses owned by the client on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for World Chain developers building sybil-resistant applications in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/world-chain/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/world-chain/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - World Chain RPC Method

# eth_blockNumber - World Chain RPC Method

Returns the number of the most recent block on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_blockNumber` is fundamental for World Chain developers building sybil-resistant applications:

- **Syncing Applications** - Keep your dApp in sync with the latest World Chain blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on human-verified DeFi, identity-gated applications, bot-resistant services
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('World Chain block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('World Chain block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'World Chain block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'World Chain block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("World Chain block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on World Chain:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on World Chain:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your World Chain node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/world-chain/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/world-chain/eth_syncing) - Check if node is still syncing

---

## eth_call - World Chain RPC Method

# eth_call - World Chain RPC Method

Executes a new message call immediately without creating a transaction on World Chain. Used for reading smart contract state.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

The `eth_call` method serves these key scenarios for World Chain developers building sybil-resistant applications:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on World Chain
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on human-verified DeFi, identity-gated applications, bot-resistant services

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on World Chain. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on World Chain
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on World Chain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - World Chain RPC Method

# eth_chainId - World Chain RPC Method

Returns the chain ID used for transaction signing on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_chainId` is essential for World Chain developers building sybil-resistant applications:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on human-verified DeFi, identity-gated applications, bot-resistant services

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/world-chain/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/world-chain/eth_syncing) - Check sync status

---

## eth_coinbase - World Chain RPC Method

# eth_coinbase - World Chain RPC Method

Checks the legacy `eth_coinbase` compatibility method on World Chain. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for World Chain developers building sybil-resistant applications when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('World Chain coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('World Chain coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'World Chain coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'World Chain coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("World Chain coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of World Chain nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/world-chain/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/world-chain/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/world-chain/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - World Chain RPC Method

# eth_estimateGas - World Chain RPC Method

Estimates the gas necessary to execute a transaction on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for World Chain developers building sybil-resistant applications:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for human-verified DeFi, identity-gated applications, bot-resistant services
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on World Chain
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on World Chain.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like World Chain may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/world-chain/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - World Chain RPC Method

# eth_feeHistory - World Chain RPC Method

Returns historical gas fee data on World Chain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for World Chain developers building sybil-resistant applications:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for human-verified DeFi, identity-gated applications, bot-resistant services
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on World Chain without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on World Chain.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on World Chain) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/world-chain/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/world-chain/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - World Chain RPC Method

# eth_gasPrice - World Chain RPC Method

Returns the current gas price on World Chain in wei.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for World Chain developers building sybil-resistant applications:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on World Chain
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of World Chain. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on World Chain, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on World Chain: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if World Chain supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/world-chain/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/world-chain/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - World Chain RPC Method

# eth_getBalance - World Chain RPC Method

Returns the balance of a given address on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getBalance` is fundamental for World Chain developers building sybil-resistant applications:

- **Wallet applications**: Display user balances and enable balance-dependent operations on World Chain
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to World Chain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across human-verified DeFi, identity-gated applications, bot-resistant services
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on World Chain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} World Chain`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on World Chain at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 World Chain')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 World Chain')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on World Chain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/world-chain/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/world-chain/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - World Chain RPC Method

# eth_getBlockByHash - World Chain RPC Method

Returns information about a block by hash on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getBlockByHash` is essential for World Chain developers building sybil-resistant applications:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on World Chain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the human-first Ethereum L2 powered by World ID
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for human-verified DeFi, identity-gated applications, bot-resistant services
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on World Chain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the human-first Ethereum L2 powered by World ID.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on World Chain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/world-chain/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - World Chain RPC Method

# eth_getBlockByNumber - World Chain RPC Method

Returns information about a block by block number on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getBlockByNumber` is essential for World Chain developers building sybil-resistant applications:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on World Chain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for human-verified DeFi, identity-gated applications, bot-resistant services
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the human-first Ethereum L2 powered by World ID

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on World Chain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on World Chain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the human-first Ethereum L2 powered by World ID expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/world-chain/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/world-chain/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/world-chain/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - World Chain RPC Method

# eth_getBlockReceipts - World Chain RPC Method

Returns all transaction receipts for a block on World Chain. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getBlockReceipts` is useful for World Chain developers building sybil-resistant applications:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for human-verified DeFi, identity-gated applications, bot-resistant services
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for World Chain, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on World Chain. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the human-first Ethereum L2 powered by World ID, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0xf676ce50d7e399fbe87b70e8d2770e3810e478912e7bcf7ac019f4398e97e3b1",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/world-chain/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/world-chain/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - World Chain RPC Method

# eth_getCode - World Chain RPC Method

Returns the bytecode at a given address on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getCode` is essential for World Chain developers building sybil-resistant applications:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on World Chain
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on human-verified DeFi, identity-gated applications, bot-resistant services

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on World Chain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on World Chain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/world-chain/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/world-chain/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - World Chain RPC Method

# eth_getFilterChanges - World Chain RPC Method

Polls a filter on World Chain for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getFilterChanges` is essential for World Chain developers building sybil-resistant applications:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on World Chain
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for human-verified DeFi, identity-gated applications, bot-resistant services
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on World Chain:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/world-chain/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/world-chain/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/world-chain/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/world-chain/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/world-chain/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - World Chain RPC Method

# eth_getFilterLogs - World Chain RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on World Chain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getFilterLogs` is essential for World Chain developers building sybil-resistant applications:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on World Chain
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/world-chain/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/world-chain/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/world-chain/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/world-chain/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - World Chain RPC Method

# eth_getLogs - World Chain RPC Method

Returns an array of all logs matching a given filter object on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for World Chain developers building sybil-resistant applications:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on World Chain for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across human-verified DeFi, identity-gated applications, bot-resistant services
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on World Chain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on World Chain.

```javascript
const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if World Chain enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on World Chain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/world-chain/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/world-chain/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - World Chain RPC Method

# eth_getStorageAt - World Chain RPC Method

Returns the value from a storage position at a given address on World Chain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getStorageAt` is essential for World Chain developers building sybil-resistant applications:

- **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 human-verified DeFi, identity-gated applications, bot-resistant services
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-worldchain-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 = '0x4200000000000000000000000000000000000006'
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-worldchain-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-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 World Chain:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-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-worldchain-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 = '0x4200000000000000000000000000000000000006';
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 World Chain:`);
  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/world-chain/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/world-chain/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/world-chain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - World Chain RPC Method

# eth_getTransactionByHash - World Chain RPC Method

Returns the information about a transaction by transaction hash on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getTransactionByHash` is essential for World Chain developers building sybil-resistant applications:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on World Chain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for human-verified DeFi, identity-gated applications, bot-resistant services
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the human-first Ethereum L2 powered by World ID

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on World Chain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on World Chain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the human-first Ethereum L2 powered by World ID.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/world-chain/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - World Chain RPC Method

# eth_getTransactionCount - World Chain RPC Method

Returns the number of transactions sent from an address on World Chain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getTransactionCount` is essential for World Chain developers building sybil-resistant applications:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on World Chain
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on human-verified DeFi, identity-gated applications, bot-resistant services
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('World Chain nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'World Chain nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("World Chain nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on World Chain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/world-chain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/world-chain/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/world-chain/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - World Chain RPC Method

# eth_getTransactionReceipt - World Chain RPC Method

Returns the receipt of a transaction by transaction hash on World Chain. Receipt is only available for mined transactions.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_getTransactionReceipt` is essential for World Chain developers building sybil-resistant applications:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on World Chain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for human-verified DeFi, identity-gated applications, bot-resistant services
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the human-first Ethereum L2 powered by World ID by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on World Chain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on World Chain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the human-first Ethereum L2 powered by World ID. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the human-first Ethereum L2 powered by World ID
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x9a2df50a4f8a32c3e0695d0fff3b51574e1aac9cc1f1962f92532a80dfb7ccda")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/world-chain/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/world-chain/eth_getLogs) - Query logs by filter

---

## eth_hashrate - World Chain RPC Method

# eth_hashrate - World Chain RPC Method

Returns the legacy `eth_hashrate` compatibility value on World Chain. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for World Chain developers building sybil-resistant applications:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('World Chain hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('World Chain hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'World Chain hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'World Chain hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("World Chain hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/world-chain/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/world-chain/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/world-chain/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - World Chain RPC Method

# eth_maxPriorityFeePerGas - World Chain RPC Method

Returns the current suggested priority fee (tip) per gas in wei on World Chain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for World Chain developers building sybil-resistant applications:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on World Chain
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on human-verified DeFi, identity-gated applications, bot-resistant services
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('World Chain priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'World Chain priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("World Chain priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on World Chain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on World Chain:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/world-chain/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/world-chain/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/world-chain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - World Chain RPC Method

# eth_mining - World Chain RPC Method

Checks the legacy `eth_mining` compatibility method on World Chain. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for World Chain developers building sybil-resistant applications:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('World Chain mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('World Chain mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'World Chain mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'World Chain mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("World Chain mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/world-chain/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/world-chain/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/world-chain/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - World Chain RPC Method

# eth_newBlockFilter - World Chain RPC Method

Creates a filter on World Chain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_newBlockFilter` is essential for World Chain developers building sybil-resistant applications:

- **Block Monitoring** - Detect new blocks on World Chain as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on World Chain:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/world-chain/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/world-chain/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/world-chain/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/world-chain/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - World Chain RPC Method

# eth_newFilter - World Chain RPC Method

Creates a filter object on World Chain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_newFilter` is essential for World Chain developers building sybil-resistant applications:

- **Event Monitoring** - Subscribe to specific contract events on World Chain such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to human-verified DeFi, identity-gated applications, bot-resistant services
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on World Chain:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/world-chain/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/world-chain/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/world-chain/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/world-chain/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/world-chain/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - World Chain RPC Method

# eth_newPendingTransactionFilter - World Chain RPC Method

Creates a filter on World Chain that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for World Chain developers building sybil-resistant applications:

- **Mempool Monitoring** - Observe unconfirmed transactions on World Chain to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for human-verified DeFi, identity-gated applications, bot-resistant services

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on World Chain...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on World Chain:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/world-chain/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/world-chain/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/world-chain/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - World Chain RPC Method

# eth_protocolVersion - World Chain RPC Method

Returns the current Ethereum protocol version used by the World Chain node.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_protocolVersion` is useful for World Chain developers building sybil-resistant applications:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('World Chain protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('World Chain protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'World Chain protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'World Chain protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("World Chain protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of World Chain nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/world-chain/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/world-chain/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/world-chain/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - World Chain RPC Method

# eth_sendRawTransaction - World Chain RPC Method

Submits a pre-signed transaction for broadcast to World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for World Chain developers building sybil-resistant applications:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to World Chain
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the World Chain mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/world-chain/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/world-chain/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/world-chain/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - World Chain RPC Method

# eth_sendTransaction - World Chain RPC Method

Creates and sends a new transaction from an unlocked account on World Chain. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for World Chain developers building sybil-resistant applications in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('World Chain tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('World Chain tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'World Chain tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'World Chain tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("World Chain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on World Chain dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/world-chain/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/world-chain/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - World Chain RPC Method

# eth_signTransaction - World Chain RPC Method

Signs a transaction with the private key of the specified account on World Chain without submitting it to the network.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for World Chain developers building sybil-resistant applications in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed World Chain tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed World Chain tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed World Chain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on World Chain:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/world-chain/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/world-chain/eth_accounts) - List accounts available for signing

---

## eth_syncing - World Chain RPC Method

# eth_syncing - World Chain RPC Method

Returns the sync status of your World Chain node - either `false` when fully synced, or an object describing the sync progress.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_syncing` is essential for World Chain developers building sybil-resistant applications:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('World Chain node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('World Chain node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("World Chain node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/world-chain/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/world-chain/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/world-chain/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/world-chain/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - World Chain RPC Method

# eth_uninstallFilter - World Chain RPC Method

Removes a filter on World Chain that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`eth_uninstallFilter` is important for World Chain developers building sybil-resistant applications:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/world-chain/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/world-chain/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/world-chain/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/world-chain/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/world-chain/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - World Chain RPC Method

# net_listening - World Chain RPC Method

Checks whether the connected World Chain client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`net_listening` is useful for World Chain developers building sybil-resistant applications:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('World Chain node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'World Chain node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("World Chain node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/world-chain/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/world-chain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/world-chain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/world-chain/web3_clientVersion) - Get node client info

---

## net_peerCount - World Chain RPC Method

# net_peerCount - World Chain RPC Method

Returns the number of peers currently connected to your World Chain node.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`net_peerCount` is important for World Chain developers building sybil-resistant applications:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific World Chain deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`World Chain peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'World Chain peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("World Chain peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of World Chain nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/world-chain/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/world-chain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/world-chain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/world-chain/web3_clientVersion) - Get node client info

---

## net_version - World Chain RPC Method

# net_version - World Chain RPC Method

Returns the current network ID on World Chain as a decimal string. The network ID identifies which network the node is connected to.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`net_version` is essential for World Chain developers building sybil-resistant applications:

- **Endpoint Identification** - Confirm your application is connected to the expected World Chain network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('World Chain network ID:', networkId);

// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'World Chain network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("World Chain network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/world-chain/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/world-chain/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/world-chain/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/world-chain/eth_syncing) - Check node sync progress

---

## web3_clientVersion - World Chain RPC Method

# web3_clientVersion - World Chain RPC Method

Returns the current client software version string for your World Chain node, including the client name, version number, OS, and runtime.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

## When to Use This Method

`web3_clientVersion` is valuable for World Chain developers building sybil-resistant applications:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('World Chain client:', clientVersion);

// Using fetch
const response = await fetch('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'World Chain client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("World Chain client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/world-chain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/world-chain/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/world-chain/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/world-chain/net_peerCount) - Get number of connected peers

---

## web3_sha3 - World Chain RPC Method

# web3_sha3 - World Chain RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on World Chain.

> **Why World Chain?** Build on the human-first Ethereum L2 powered by World ID with World ID integration for free gas and priority blockspace.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for World Chain developers building sybil-resistant applications:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-worldchain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/world-chain/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/world-chain/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/world-chain/web3_clientVersion) - Get node client version

---

## XDC Network, Enterprise-Grade Hybrid Blockchain

# XDC Network, Enterprise-Grade Hybrid Blockchain

## XDC Network RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where XDC Network supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on XDC Network

- **Enterprise ready:** Optimized for trade finance, tokenized real-world assets, and enterprise-grade integrations
- **Hybrid architecture:** Public network with optional private state channels for sensitive data
- **Ethereum-compatible tooling:** Seamless migration for Solidity smart contracts and EVM tooling
- **ISO 20022 alignment:** Built with financial messaging standards and compliance workflows in mind
- **Efficient consensus:** XinFin Delegated Proof of Stake (XDPoS) delivers \~2 second block times and low fees

## Quick Start

### Connect Endpoints

## Network Information

| Parameter          | Value              | Details |
| ------------------ | ------------------ | ------- |
| Mainnet Chain ID   | 50 (0x32)          |         |
| Testnet Chain ID   | 51 (0x33), Apothem |         |
| Native Token       | XDC                |         |
| Average Block Time | \~2 seconds        |         |

## Installation & Setup

Ethers.js v6
Web3.js
Viem
web3.py

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to XDC Network mainnet
const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Verify connection
const { chainId } = await provider.getNetwork();
console.log('Connected to XDC Network:', chainId === 50n);

// Fetch latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);
```

```javascript
import Web3 from 'web3';

const web3 = new Web3('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const chainId = await web3.eth.getChainId();
console.log('Connected to XDC Network:', chainId === 50);

const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price (XDC):', gasPrice);
```

```typescript
import { createPublicClient, defineChain, http } from 'viem';

const xdc = defineChain({
  id: 50,
  name: 'XDC Network',
  nativeCurrency: { name: 'XDC', symbol: 'XDC', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'] }
  }
});

const client = createPublicClient({ chain: xdc, transport: http() });

const blockNumber = await client.getBlockNumber();
console.log('Latest block:', blockNumber);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

if w3.is_connected():
    chain_id = w3.eth.chain_id
    print(f'Connected to XDC Network (chain ID: {chain_id})')

balance = w3.eth.get_balance('0x0000000000000000000000000000000000000000')
print('Foundation balance (wei):', balance)
```

### Consensus & Validator Model

| Parameter     | Value     | Details                   |
| ------------- | --------- | ------------------------- |
| Consensus     | XDPoS 2.0 | Delegated Proof of Stake  |
| Finality      | \~2s      | Fast settlement           |
| Validator Set | 108       | Masternodes and delegates |

## Core Features

- **Hybrid privacy:** Permissionless public ledger with optional private side-channels for data confidentiality
- **Low cost transactions:** Typical fees under $0.0002 per transfer, enabling micro-settlement use cases
- **Asset tokenization:** Native support for security tokens, invoice financing, and RWA issuance
- **Interoperability:** Bridges to Ethereum, Polygon, BNB Chain, and Corda-based networks
- **Regulatory readiness:** Compliance-first tooling, identity layers, and notarization workflows

## API Reference

Detailed method guides for XDC Network are coming soon. Standard Ethereum JSON-RPC calls (`eth_blockNumber`, `eth_getBalance`, `eth_sendRawTransaction`, etc.) are fully supported today.

Reach out to the Dwellir team if you need a specific method guide prioritized.

## Tooling & Integrations

- **Explorer**: [XDC Scan](https://xdcscan.io/)
- **Faucet**: [Apothem Faucet](https://faucet.apothem.network/)
- **Wallets**: XDC Pay, Ledger (with Chainlist), D'Cent
- **Bridges**: XDC Web Wallet bridge, Prime Numbers bridge

## Developer Resources

- [Official XDC Documentation](https://docs.xdc.network/)
- [XDC Developer Forum](https://www.xdc.dev/)
- [XinFin GitHub](https://github.com/xinfinorg)
- [Quick Start Guide](https://docs.xdc.network/xdcchain/developers/quick-guide/)

## Next Steps

1. Request your dedicated API key from the Dwellir dashboard
2. Point your existing EVM tooling to the endpoints above
3. Start deploying Solidity contracts or minting assets on XDC Network

Build confidently on XDC Network with globally distributed, low-latency RPC access from Dwellir.

---

## debug_traceBlock - XDC Network RPC Method

# debug_traceBlock - XDC Network RPC Method

Traces all transactions in a block on XDC Network by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for XDC Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on XDC Network
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on XDC Network:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in XDC Network blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/xdc-network/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/xdc-network/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - XDC Network RPC Method

# debug_traceBlockByHash - XDC Network RPC Method

Traces all transactions in a block on XDC Network identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for XDC Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on XDC Network
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on XDC Network:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on XDC Network:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/xdc-network/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/xdc-network/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/xdc-network/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - XDC Network RPC Method

# debug_traceBlockByNumber - XDC Network RPC Method

Traces all transactions in a block on XDC Network identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for XDC Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of XDC Network execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on XDC Network:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on XDC Network:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/xdc-network/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/xdc-network/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/xdc-network/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - XDC Network RPC Method

# debug_traceCall - XDC Network RPC Method

Traces a call on XDC Network without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for XDC Network - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on XDC Network
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "data": "0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
        "data": "0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
        "data": "0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x951857744785E80e2De051c32EE7b25f9c458C42',
    data: '0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x951857744785E80e2De051c32EE7b25f9c458C42',
    data: '0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x951857744785E80e2De051c32EE7b25f9c458C42',
    'data': '0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x951857744785E80e2De051c32EE7b25f9c458C42",
        "data": "0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on XDC Network to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on XDC Network:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on XDC Network:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x951857744785E80e2De051c32EE7b25f9c458C42',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/xdc-network/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/xdc-network/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - XDC Network RPC Method

# debug_traceTransaction - XDC Network RPC Method

Traces a transaction execution on XDC Network by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on XDC Network
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/xdc-network/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/xdc-network/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - XDC Network RPC Method

# eth_accounts - XDC Network RPC Method

Returns a list of addresses owned by the client on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for trade finance developers, enterprise blockchain teams, and RWA tokenization builders in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/xdc-network/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - XDC Network RPC Method

# eth_blockNumber - XDC Network RPC Method

Returns the number of the most recent block on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_blockNumber` is fundamental for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Syncing Applications** - Keep your dApp in sync with the latest XDC Network blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('XDC Network block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('XDC Network block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'XDC Network block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'XDC Network block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("XDC Network block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on XDC Network:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on XDC Network:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your XDC Network node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/xdc-network/eth_syncing) - Check if node is still syncing

---

## eth_call - XDC Network RPC Method

# eth_call - XDC Network RPC Method

Executes a new message call immediately without creating a transaction on XDC Network. Used for reading smart contract state.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

The `eth_call` method serves these key scenarios for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on XDC Network
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x951857744785E80e2De051c32EE7b25f9c458C42';
const walletAddress = '0x951857744785E80e2De051c32EE7b25f9c458C42';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on XDC Network. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x951857744785E80e2De051c32EE7b25f9c458C42';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x951857744785E80e2De051c32EE7b25f9c458C42';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on XDC Network
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on XDC Network

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "data": "0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "data": "0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x951857744785E80e2De051c32EE7b25f9c458C42',
    '0x951857744785E80e2De051c32EE7b25f9c458C42'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    data := common.FromHex("0x70a08231000000000000000000000000951857744785E80e2De051c32EE7b25f9c458C42")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - XDC Network RPC Method

# eth_chainId - XDC Network RPC Method

Returns the chain ID used for transaction signing on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_chainId` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/xdc-network/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/xdc-network/eth_syncing) - Check sync status

---

## eth_coinbase - XDC Network RPC Method

# eth_coinbase - XDC Network RPC Method

Checks the legacy `eth_coinbase` compatibility method on XDC Network. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for trade finance developers, enterprise blockchain teams, and RWA tokenization builders when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('XDC Network coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('XDC Network coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'XDC Network coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'XDC Network coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("XDC Network coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of XDC Network nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/xdc-network/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/xdc-network/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/xdc-network/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - XDC Network RPC Method

# eth_estimateGas - XDC Network RPC Method

Estimates the gas necessary to execute a transaction on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on XDC Network
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x951857744785E80e2De051c32EE7b25f9c458C42', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x951857744785E80e2De051c32EE7b25f9c458C42', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on XDC Network.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like XDC Network may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x951857744785E80e2De051c32EE7b25f9c458C42',
  '0x951857744785E80e2De051c32EE7b25f9c458C42',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "to": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x951857744785E80e2De051c32EE7b25f9c458C42', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/xdc-network/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - XDC Network RPC Method

# eth_feeHistory - XDC Network RPC Method

Returns historical gas fee data on XDC Network, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on XDC Network without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on XDC Network.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on XDC Network) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/xdc-network/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/xdc-network/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - XDC Network RPC Method

# eth_gasPrice - XDC Network RPC Method

Returns the current gas price on XDC Network in wei.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on XDC Network
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of XDC Network. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on XDC Network, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on XDC Network: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if XDC Network supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/xdc-network/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/xdc-network/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - XDC Network RPC Method

# eth_getBalance - XDC Network RPC Method

Returns the balance of a given address on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getBalance` is fundamental for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Wallet applications**: Display user balances and enable balance-dependent operations on XDC Network
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to XDC Network
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on XDC Network. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} XDC Network`);
  return balance;
}

displayBalance('0x951857744785E80e2De051c32EE7b25f9c458C42');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on XDC Network at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x951857744785E80e2De051c32EE7b25f9c458C42'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 XDC Network')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 XDC Network')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on XDC Network.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x951857744785E80e2De051c32EE7b25f9c458C42';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x951857744785E80e2De051c32EE7b25f9c458C42'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/xdc-network/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - XDC Network RPC Method

# eth_getBlockByHash - XDC Network RPC Method

Returns information about a block by hash on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getBlockByHash` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on XDC Network
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on XDC Network.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on XDC Network.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - XDC Network RPC Method

# eth_getBlockByNumber - XDC Network RPC Method

Returns information about a block by block number on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getBlockByNumber` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on XDC Network
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on XDC Network with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on XDC Network. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - XDC Network RPC Method

# eth_getBlockReceipts - XDC Network RPC Method

Returns all transaction receipts for a block on XDC Network. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getBlockReceipts` is useful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for XDC Network, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on XDC Network. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x07c1ce3b8528b00e72e875f5527a4913a08d22c1ac8fec8744cf8a6b75b4e885",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - XDC Network RPC Method

# eth_getCode - XDC Network RPC Method

Returns the bytecode at a given address on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getCode` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on XDC Network
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on XDC Network:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on XDC Network:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x951857744785E80e2De051c32EE7b25f9c458C42';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x951857744785E80e2De051c32EE7b25f9c458C42'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/xdc-network/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/xdc-network/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - XDC Network RPC Method

# eth_getFilterChanges - XDC Network RPC Method

Polls a filter on XDC Network for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getFilterChanges` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on XDC Network
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x951857744785E80e2De051c32EE7b25f9c458C42',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x951857744785E80e2De051c32EE7b25f9c458C42'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on XDC Network:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/xdc-network/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/xdc-network/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/xdc-network/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/xdc-network/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/xdc-network/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - XDC Network RPC Method

# eth_getFilterLogs - XDC Network RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on XDC Network. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getFilterLogs` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on XDC Network
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x951857744785E80e2De051c32EE7b25f9c458C42"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x951857744785E80e2De051c32EE7b25f9c458C42',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x951857744785E80e2De051c32EE7b25f9c458C42'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/xdc-network/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/xdc-network/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/xdc-network/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/xdc-network/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - XDC Network RPC Method

# eth_getLogs - XDC Network RPC Method

Returns an array of all logs matching a given filter object on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on XDC Network for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on XDC Network
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x951857744785E80e2De051c32EE7b25f9c458C42';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x951857744785E80e2De051c32EE7b25f9c458C42';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on XDC Network.

```javascript
const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if XDC Network enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on XDC Network, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x951857744785E80e2De051c32EE7b25f9c458C42',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x951857744785E80e2De051c32EE7b25f9c458C42',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/xdc-network/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/xdc-network/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - XDC Network RPC Method

# eth_getStorageAt - XDC Network RPC Method

Returns the value from a storage position at a given address on XDC Network. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getStorageAt` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **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 tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **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": [
    "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "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-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x951857744785E80e2De051c32EE7b25f9c458C42', '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-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x951857744785E80e2De051c32EE7b25f9c458C42';

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-xdc-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 = '0x951857744785E80e2De051c32EE7b25f9c458C42'
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-xdc-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-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    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 XDC Network:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-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-xdc-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 = '0x951857744785E80e2De051c32EE7b25f9c458C42';
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 XDC Network:`);
  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/xdc-network/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/xdc-network/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/xdc-network/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - XDC Network RPC Method

# eth_getTransactionByHash - XDC Network RPC Method

Returns the information about a transaction by transaction hash on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getTransactionByHash` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on XDC Network
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on XDC Network. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on XDC Network. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - XDC Network RPC Method

# eth_getTransactionCount - XDC Network RPC Method

Returns the number of transactions sent from an address on XDC Network, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getTransactionCount` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on XDC Network
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x951857744785E80e2De051c32EE7b25f9c458C42', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('XDC Network nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x951857744785E80e2De051c32EE7b25f9c458C42';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x951857744785E80e2De051c32EE7b25f9c458C42'
nonce = get_transaction_count(address)
print(f'XDC Network nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("XDC Network nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on XDC Network:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x951857744785E80e2De051c32EE7b25f9c458C42');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/xdc-network/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - XDC Network RPC Method

# eth_getTransactionReceipt - XDC Network RPC Method

Returns the receipt of a transaction by transaction hash on XDC Network. Receipt is only available for mined transactions.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_getTransactionReceipt` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on XDC Network and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on XDC Network. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on XDC Network, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x60975ea1a0c8283193d6b1ea0b8ea7d37745e30703eeb15f82a3acf1c72ce8f3")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/xdc-network/eth_getLogs) - Query logs by filter

---

## eth_hashrate - XDC Network RPC Method

# eth_hashrate - XDC Network RPC Method

Returns the legacy `eth_hashrate` compatibility value on XDC Network. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('XDC Network hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('XDC Network hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'XDC Network hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'XDC Network hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("XDC Network hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/xdc-network/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/xdc-network/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - XDC Network RPC Method

# eth_maxPriorityFeePerGas - XDC Network RPC Method

Returns the current suggested priority fee (tip) per gas in wei on XDC Network. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on XDC Network
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('XDC Network priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'XDC Network priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("XDC Network priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on XDC Network:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on XDC Network:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/xdc-network/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/xdc-network/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - XDC Network RPC Method

# eth_mining - XDC Network RPC Method

Checks the legacy `eth_mining` compatibility method on XDC Network. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('XDC Network mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('XDC Network mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'XDC Network mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'XDC Network mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("XDC Network mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/xdc-network/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/xdc-network/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - XDC Network RPC Method

# eth_newBlockFilter - XDC Network RPC Method

Creates a filter on XDC Network that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_newBlockFilter` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Block Monitoring** - Detect new blocks on XDC Network as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on XDC Network:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/xdc-network/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/xdc-network/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/xdc-network/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - XDC Network RPC Method

# eth_newFilter - XDC Network RPC Method

Creates a filter object on XDC Network based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_newFilter` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Event Monitoring** - Subscribe to specific contract events on XDC Network such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x951857744785E80e2De051c32EE7b25f9c458C42",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x951857744785E80e2De051c32EE7b25f9c458C42",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x951857744785E80e2De051c32EE7b25f9c458C42',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x951857744785E80e2De051c32EE7b25f9c458C42',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on XDC Network:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x951857744785E80e2De051c32EE7b25f9c458C42',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/xdc-network/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/xdc-network/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/xdc-network/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/xdc-network/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/xdc-network/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - XDC Network RPC Method

# eth_newPendingTransactionFilter - XDC Network RPC Method

Creates a filter on XDC Network that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Mempool Monitoring** - Observe unconfirmed transactions on XDC Network to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for tokenized trade finance (Letters of Credit, Bills of Lading), cross-border payments, and real-world asset tokenization

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on XDC Network...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on XDC Network:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/xdc-network/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/xdc-network/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - XDC Network RPC Method

# eth_protocolVersion - XDC Network RPC Method

Returns the current Ethereum protocol version used by the XDC Network node.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_protocolVersion` is useful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('XDC Network protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('XDC Network protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'XDC Network protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'XDC Network protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("XDC Network protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of XDC Network nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/xdc-network/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/xdc-network/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/xdc-network/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - XDC Network RPC Method

# eth_sendRawTransaction - XDC Network RPC Method

Submits a pre-signed transaction for broadcast to XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to XDC Network
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x951857744785E80e2De051c32EE7b25f9c458C42', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the XDC Network mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/xdc-network/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x951857744785E80e2De051c32EE7b25f9c458C42")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/xdc-network/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - XDC Network RPC Method

# eth_sendTransaction - XDC Network RPC Method

Creates and sends a new transaction from an unlocked account on XDC Network. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('XDC Network tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('XDC Network tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'XDC Network tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'XDC Network tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("XDC Network tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on XDC Network dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/xdc-network/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/xdc-network/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - XDC Network RPC Method

# eth_signTransaction - XDC Network RPC Method

Signs a transaction with the private key of the specified account on XDC Network without submitting it to the network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for trade finance developers, enterprise blockchain teams, and RWA tokenization builders in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed XDC Network tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed XDC Network tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed XDC Network tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on XDC Network:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/xdc-network/eth_accounts) - List accounts available for signing

---

## eth_syncing - XDC Network RPC Method

# eth_syncing - XDC Network RPC Method

Returns the sync status of your XDC Network node - either `false` when fully synced, or an object describing the sync progress.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_syncing` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('XDC Network node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('XDC Network node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("XDC Network node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/xdc-network/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/xdc-network/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/xdc-network/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - XDC Network RPC Method

# eth_uninstallFilter - XDC Network RPC Method

Removes a filter on XDC Network that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`eth_uninstallFilter` is important for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/xdc-network/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/xdc-network/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/xdc-network/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/xdc-network/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/xdc-network/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - XDC Network RPC Method

# net_listening - XDC Network RPC Method

Checks whether the connected XDC Network client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`net_listening` is useful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('XDC Network node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'XDC Network node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("XDC Network node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/xdc-network/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/xdc-network/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/xdc-network/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/xdc-network/web3_clientVersion) - Get node client info

---

## net_peerCount - XDC Network RPC Method

# net_peerCount - XDC Network RPC Method

Returns the number of peers currently connected to your XDC Network node.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`net_peerCount` is important for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific XDC Network deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`XDC Network peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'XDC Network peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("XDC Network peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of XDC Network nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/xdc-network/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/xdc-network/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/xdc-network/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/xdc-network/web3_clientVersion) - Get node client info

---

## net_version - XDC Network RPC Method

# net_version - XDC Network RPC Method

Returns the current network ID on XDC Network as a decimal string. The network ID identifies which network the node is connected to.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`net_version` is essential for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Endpoint Identification** - Confirm your application is connected to the expected XDC Network network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('XDC Network network ID:', networkId);

// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'XDC Network network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("XDC Network network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/xdc-network/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/xdc-network/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/xdc-network/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/xdc-network/eth_syncing) - Check node sync progress

---

## rpc_modules - XDC Network RPC Method

# rpc_modules - XDC Network RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected XDC Network endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`rpc_modules` is useful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/xdc-network/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/xdc-network/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - XDC Network RPC Method

# txpool_content - XDC Network RPC Method

Returns the full pending and queued transaction pool for the connected XDC Network endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`txpool_content` is useful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/xdc-network/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/xdc-network/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/xdc-network/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - XDC Network RPC Method

# txpool_status - XDC Network RPC Method

Returns transaction pool counters for the connected XDC Network endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`txpool_status` is valuable for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/xdc-network/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/xdc-network/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/xdc-network/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - XDC Network RPC Method

# web3_clientVersion - XDC Network RPC Method

Returns the current client software version string for your XDC Network node, including the client name, version number, OS, and runtime.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

## When to Use This Method

`web3_clientVersion` is valuable for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('XDC Network client:', clientVersion);

// Using fetch
const response = await fetch('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'XDC Network client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("XDC Network client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/xdc-network/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/xdc-network/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/xdc-network/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/xdc-network/net_peerCount) - Get number of connected peers

---

## web3_sha3 - XDC Network RPC Method

# web3_sha3 - XDC Network RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on XDC Network.

> **Why XDC Network?** Build on the enterprise-grade blockchain for trade finance with 2-second finality and ISO 20022 compliance with ISO 20022 messaging, ITFA membership, Contour Network acquisition, 801M+ transactions, and partnerships with Circle and Deutsche Telekom.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for trade finance developers, enterprise blockchain teams, and RWA tokenization builders:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/xdc-network/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/xdc-network/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/xdc-network/web3_clientVersion) - Get node client version

---

## xx Network RPC Documentation

# xx Network RPC Documentation

## xx Network RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where xx Network supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Overview

xx Network is the world's first quantum-resistant, privacy-first Layer 1 blockchain, founded by cryptography pioneer David Chaum. Built on the Substrate framework, xx Network features revolutionary metadata shredding technology (cMixx) that obscures transaction patterns and protects against quantum computing attacks.

This documentation provides comprehensive coverage of xx Network's JSON-RPC API methods, enabling developers to interact with xx Network nodes for building applications, wallets, explorers, and other blockchain tools.

## Network Information

### Mainnet (xx Network)

| Parameter        | Value                                         | Details |
| ---------------- | --------------------------------------------- | ------- |
| Native Token     | XX                                            |         |
| Consensus        | Nominated Proof-of-Stake (NPoS)               |         |
| Block Time       | \~6 seconds                                   |         |
| Framework        | Substrate                                     |         |
| Special Features | Quantum-resistant, metadata shredding (cMixx) |         |

## Connection Endpoints

### HTTPS Endpoint

```
https://api-xxnetwork.n.dwellir.com/{YOUR_API_KEY}
```

### WebSocket Endpoint

```
wss://api-xxnetwork.n.dwellir.com/{YOUR_API_KEY}
```

## Authentication

Authentication is done via the URL path. Replace `{YOUR_API_KEY}` with your actual API key obtained from [dwellir.com](https://www.dwellir.com).

## API Categories

xx Network's RPC API is organized into the following method categories:

### Core APIs

#### Author Methods

Submit and manage extrinsics (transactions) on the network.

#### Chain Methods

Query blockchain data including blocks, headers, and finalized state.

#### State Methods

Access runtime storage, metadata, and proof generation.

#### System Methods

Node information, health checks, and network properties.

### Specialized APIs

#### BEEFY Methods

Bridge Efficiency Enabling Finality Yielder protocol operations.

#### Grandpa Methods

GRANDPA finality gadget operations and proofs.

#### Child State Methods

Manage child storage tries for contracts and parachains.

#### Sync State Methods

Monitor and manage node synchronization state.

## Quick Start Examples

### Get Latest Block

```javascript
const response = await fetch('https://api-xxnetwork.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_getBlock',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log('Latest block:', data.result);
```

### Submit Transaction

```python
import requests
import json

url = "https://api-xxnetwork.n.dwellir.com/YOUR_API_KEY"
headers = {
    "Content-Type": "application/json"
}

# Properly formatted and signed extrinsic
extrinsic = "0x..."

payload = {
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": [extrinsic],
    "id": 1
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
tx_hash = response.json()["result"]
print(f"Transaction hash: {tx_hash}")
```

### Subscribe to New Blocks (WebSocket)

```javascript
const WebSocket = require('ws');

const ws = new WebSocket('wss://api-xxnetwork.n.dwellir.com/YOUR_API_KEY');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'chain_subscribeNewHeads',
    params: [],
    id: 1
  }));
});

ws.on('message', (data) => {
  const response = JSON.parse(data);
  if (response.params?.result) {
    console.log('New block:', response.params.result);
  }
});
```

## Error Handling

xx Network RPC errors follow the JSON-RPC 2.0 error format:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "Expected hex-encoded hash"
  },
  "id": 1
}
```

### Common Error Codes

| Code   | Message          | Description               |
| ------ | ---------------- | ------------------------- |
| -32700 | Parse error      | Invalid JSON              |
| -32600 | Invalid request  | Missing required fields   |
| -32601 | Method not found | Unknown RPC method        |
| -32602 | Invalid params   | Invalid method parameters |
| -32603 | Internal error   | Node processing error     |
| -32000 | Server error     | Custom server errors      |

## Best Practices

### 1. Connection Management

- Use WebSocket connections for subscriptions and real-time updates
- Implement reconnection logic for WebSocket disconnections
- Use HTTPS for single queries and transactions

### 2. Error Handling

- Always check for error responses before processing results
- Implement retry logic with exponential backoff
- Log errors for debugging and monitoring

### 3. Performance Optimization

- Batch multiple queries when possible
- Cache frequently accessed data like metadata
- Use specific block hashes for deterministic queries

### 4. Security

- Never expose API keys in client-side code
- Validate all input data before submission
- Use secure storage for private keys

### 5. Privacy & Quantum Resistance

- All transactions benefit from automatic metadata shredding via cMixx
- Quantum-resistant cryptography is built into the protocol
- No special configuration required for privacy protection

## SDK Support

### Official Libraries

- **@polkadot/api** - JavaScript/TypeScript SDK (compatible with xx Network)
- **py-substrate-interface** - Python SDK
- **subxt** - Rust SDK
- **go-substrate-rpc-client** - Go SDK

### Integration Example

```javascript
// Using @polkadot/api
const { ApiPromise, WsProvider } = require('@polkadot/api');

async function connect() {
  const provider = new WsProvider('wss://api-xxnetwork.n.dwellir.com/YOUR_API_KEY');

  const api = await ApiPromise.create({ provider });

  // Query chain data
  const chain = await api.rpc.system.chain();
  console.log(`Connected to ${chain}`);

  // Get account balance
  const account = 'YOUR_ADDRESS';
  const { data: balance } = await api.query.system.account(account);
  console.log(`Balance: ${balance.free.toString()}`);

  return api;
}
```

## Privacy Features

### cMixx Metadata Shredding

xx Network's revolutionary cMixx protocol automatically obscures transaction metadata, preventing third parties from connecting senders to recipients. This happens transparently for all transactions:

```javascript
// Standard transfer - metadata is automatically shredded
const transfer = api.tx.balances.transfer(recipient, amount);
const hash = await transfer.signAndSend(senderKeyPair);

// Privacy protection is built-in, no special configuration needed
```

### Quantum-Resistant Cryptography

All transactions on xx Network are protected against quantum computing attacks using post-quantum cryptographic primitives. Your applications are future-proof by default.

## Additional Resources

- [xx Network Website](https://xx.network/)
- [xx Network 2025 Roadmap](https://xx.network/blog/xx-network-unveils-2025-roadmap/)
- [Substrate Documentation](https://docs.substrate.io/)
- [xx Network Explorer](https://explorer.xx.network/)

## Support

For additional support or questions:

- Email: <support@dwellir.com>
- Documentation: [dwellir.com/docs](https://www.dwellir.com/docs)

***

## Method Categories

Select a category below to explore detailed method documentation:

---

## author_pendingExtrinsics - XX Network RPC Method

# author_pendingExtrinsics - XX Network RPC Method

Returns all pending extrinsics currently in the transaction pool on XX Network. These are signed extrinsics that have been submitted but not yet included in a finalized block.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`author_pendingExtrinsics` is essential for XX Network developers building privacy-preserving applications:

- **Transaction Confirmation** -- Verify whether a submitted extrinsic is still pending or has been included in a block on XX Network
- **Mempool Monitoring** -- Monitor the transaction pool size and activity for secure messaging, private payments, and quantum-resistant cryptography
- **Network Congestion Analysis** -- Gauge current network load by inspecting the number and type of pending extrinsics
- **Validator Tooling** -- Build block authoring tools that inspect the ready queue before producing blocks

## Best Practices

- Response can be large on congested networks -- filter by sender address client-side
- Not available on all node configurations (some providers disable author namespace)
- Use for mempool inspection and transaction congestion diagnosis
- Pending extrinsics are not guaranteed to be included -- monitor with confirmation polling

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_pendingExtrinsics",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded SCALE-encoded signed extrinsics currently in the transaction pool

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x2d0284ff...",
    "0x3102840f..."
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_pendingExtrinsics",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const pending = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', pending.length);

pending.forEach((ext, idx) => {
  console.log(`${idx}: ${ext.method.section}.${ext.method.method}`);
  console.log(`   Signer: ${ext.signer.toString()}`);
  console.log(`   Nonce: ${ext.nonce.toString()}`);
  console.log(`   Tip: ${ext.tip.toString()}`);
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_pendingExtrinsics',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`${result.length} pending extrinsics in pool`);
```

```python
import requests

def get_pending_extrinsics():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_pendingExtrinsics',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

pending = get_pending_extrinsics()
print(f'Pending extrinsics: {len(pending)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('author_pendingExtrinsics', [])['result']
print(f'Pending extrinsics: {len(result)}')

for i, ext_hex in enumerate(result):
    print(f'  {i}: {ext_hex[:40]}...')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_pendingExtrinsics",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let pending = result["result"].as_array().unwrap();

    println!("Pending extrinsics: {}", pending.len());
    for (i, ext) in pending.iter().enumerate() {
        let hex = ext.as_str().unwrap();
        println!("  {}: {}...", i, &hex[..std::cmp::min(40, hex.len())]);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Transaction Pool Monitor

Continuously monitor the XX Network transaction pool and alert on unusual activity:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorPool(api, interval = 6000) {
  let previousCount = 0;

  setInterval(async () => {
    const pending = await api.rpc.author.pendingExtrinsics();
    const count = pending.length;

    if (count !== previousCount) {
      console.log(`Pool size changed: ${previousCount} -> ${count}`);

      if (count > 100) {
        console.warn('High pool activity detected!');
      }
    }

    // Analyze pending extrinsic types
    const byPallet = {};
    pending.forEach((ext) => {
      const key = `${ext.method.section}.${ext.method.method}`;
      byPallet[key] = (byPallet[key] || 0) + 1;
    });

    if (Object.keys(byPallet).length > 0) {
      console.log('Pending by type:', byPallet);
    }

    previousCount = count;
  }, interval);
}
```

### 2. Verify Transaction Submission

Check that a submitted extrinsic appears in the pool:

```javascript
async function verifyInPool(api, txHash) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const found = pending.find((ext) => ext.hash.toHex() === txHash);

  if (found) {
    console.log(`Transaction ${txHash} is in the pool`);
    console.log(`  Call: ${found.method.section}.${found.method.method}`);
    return true;
  }

  console.log(`Transaction ${txHash} not found in pool (may already be included)`);
  return false;
}
```

### 3. Pool Congestion Analysis

Analyze network congestion to decide on tip amounts:

```javascript
async function analyzeCongestion(api) {
  const pending = await api.rpc.author.pendingExtrinsics();

  const tips = pending.map((ext) => ext.tip.toBigInt());
  const totalTips = tips.reduce((sum, tip) => sum + tip, 0n);
  const avgTip = tips.length > 0 ? totalTips / BigInt(tips.length) : 0n;
  const maxTip = tips.length > 0 ? tips.reduce((a, b) => (a > b ? a : b), 0n) : 0n;

  return {
    poolSize: pending.length,
    averageTip: avgTip.toString(),
    maxTip: maxTip.toString(),
    congested: pending.length > 50
  };
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/xx-network/author_submitExtrinsic) -- Submit a signed extrinsic to the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/xx-network/payment_queryInfo) -- Estimate fees for an extrinsic before submission
- [`system_chain`](https://www.dwellir.com/docs/xx-network/system_chain) -- Get the chain name
- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) -- Get a finalized block to see which extrinsics were included

---

## author_rotateKeys - XX Network RPC Method

# author_rotateKeys - XX Network RPC Method

Generate a new set of session keys on XX Network. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`author_rotateKeys` is critical for XX Network developers building privacy-preserving applications:

- **Validator Setup** - Generate initial session keys when setting up a new validator on secure messaging, private payments, and quantum-resistant cryptography
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on XX Network:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/xx-network/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/xx-network/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain

---

## author_submitAndWatchExtrinsic - XX Network RPC Method

# author_submitAndWatchExtrinsic - XX Network RPC Method

Submits a signed extrinsic to XX Network and returns a subscription that emits status updates as the transaction progresses through the lifecycle -- from entering the transaction pool, through block inclusion, to finalization. This is a WebSocket-only subscription method.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`author_submitAndWatchExtrinsic` is essential for XX Network developers building privacy-preserving applications:

- **Transaction Lifecycle Tracking** -- Receive real-time status events as your extrinsic moves from the pool into a block and reaches finality on XX Network
- **Confirmation Waiting** -- Block until a transaction reaches a specific finality level (e.g., `inBlock` or `finalized`) before proceeding with dependent logic
- **Error Detection** -- Detect dropped, invalid, or usurped transactions immediately instead of polling, critical for secure messaging, private payments, and quantum-resistant cryptography
- **User-Facing Feedback** -- Power progress indicators and toast notifications in dApp interfaces with granular status updates

## Best Practices

- Requires a WebSocket connection for real-time status updates
- Handles multiple status transitions: Ready, Broadcast, InBlock, Finalized
- Unsubscribe from the watch subscription when the extrinsic is confirmed
- Use `author_submitExtrinsic` with polling if WebSocket is unavailable

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized signed extrinsic (e.g., output of tx.toHex() or createSignedTx(...))

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`Unknown, required`): Extrinsic placed in the future queue because its nonce is higher than expected
- `field_2` (`Unknown, required`): Extrinsic is in the ready queue, waiting to be included in a block
- `field_3` (`Unknown, required`): Extrinsic has been broadcast to the listed peer IDs
- `field_4` (`Unknown, required`): Extrinsic has been included in the block with this hash (not yet finalized)
- `field_5` (`Unknown, required`): Block containing the extrinsic was retracted due to a chain reorganization
- `field_6` (`Unknown, required`): Finality could not be reached for the block within the expected timeframe
- `field_7` (`Unknown, required`): Extrinsic has been finalized in the block with this hash
- `field_8` (`Unknown, required`): Extrinsic was replaced by another extrinsic with the same nonce (hash of replacement)
- `field_9` (`Unknown, required`): Extrinsic was dropped from the transaction pool (e.g., pool is full or fee too low)
- `field_10` (`Unknown, required`): Extrinsic failed validation (bad signature, insufficient balance, wrong nonce, etc.)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "bNxKoEf7t58opia1"
}
```

## Error Responses

### Error Response

- Code: `1002`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1002,
    "message": "Verification Error: Runtime error: Extrinsic has invalid signature"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# author_submitAndWatchExtrinsic requires WebSocket.
# Use websocat to send the subscription request:
echo '{
  "jsonrpc": "2.0",
  "method": "author_submitAndWatchExtrinsic",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}' | websocat wss://api-xxnetwork.dwellir.com/YOUR_API_KEY

# The connection stays open and prints status update messages as they arrive.
# For a fire-and-forget HTTP approach, use author_submitExtrinsic instead:
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x2d028400..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: 'sr25519' });

// Create and sign a transfer
const sender = keyring.addFromUri('//Alice');
const transfer = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Submit and watch -- signAndSend uses author_submitAndWatchExtrinsic internally
const unsub = await transfer.signAndSend(sender, ({ status, events, dispatchError }) => {
  console.log(`Status: ${status.type}`);

  if (status.isInBlock) {
    console.log(`Included in block: ${status.asInBlock.toHex()}`);

    // Check for dispatch errors in events
    if (dispatchError) {
      if (dispatchError.isModule) {
        const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
        console.error(`Error: ${section}.${name} -- ${docs.join(' ')}`);
      } else {
        console.error(`Error: ${dispatchError.toString()}`);
      }
    }
  }

  if (status.isFinalized) {
    console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
    unsub();
    api.disconnect();
  }
});

// Using raw WebSocket JSON-RPC
const ws = new WebSocket('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');

ws.onopen = () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitAndWatchExtrinsic',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.params) {
    console.log('Status update:', msg.params.result);
  } else {
    console.log('Subscription ID:', msg.result);
  }
};
```

```python
import asyncio
import websockets
import json

async def submit_and_watch(signed_extrinsic_hex):
    uri = 'wss://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Submit and subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'author_submitAndWatchExtrinsic',
            'params': [signed_extrinsic_hex],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        if 'error' in response:
            print(f"Submission error: {response['error']['message']}")
            return None

        sub_id = response['result']
        print(f'Watching with subscription: {sub_id}')

        # Listen for status updates
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                status = message['params']['result']
                print(f'Status: {status}')

                # Handle terminal states
                if isinstance(status, dict):
                    if 'finalized' in status:
                        print(f"Finalized in: {status['finalized']}")
                        return status['finalized']
                    elif 'usurped' in status:
                        print(f"Usurped by: {status['usurped']}")
                        return None
                elif status in ('dropped', 'invalid', 'finalityTimeout'):
                    print(f'Transaction failed with status: {status}')
                    return None

# asyncio.run(submit_and_watch('0x2d028400...'))

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
keypair = Keypair.create_from_uri('//Alice')

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1000000000000
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_finalization=True)
print(f'Finalized in block: {receipt.block_hash}')
print(f'Extrinsic successful: {receipt.is_success}')
```

```rust
use futures::StreamExt;
use serde_json::json;
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (mut ws_stream, _) = connect_async("https://api-xxnetwork.dwellir.com/YOUR_API_KEY").await?;

    // Send the subscription request
    let request = json!({
        "jsonrpc": "2.0",
        "method": "author_submitAndWatchExtrinsic",
        "params": ["0x2d028400...signedExtrinsicHex"],
        "id": 1
    });

    ws_stream
        .send(Message::Text(request.to_string()))
        .await?;

    // Listen for status updates
    while let Some(msg) = ws_stream.next().await {
        let msg = msg?;
        if let Message::Text(text) = msg {
            let value: serde_json::Value = serde_json::from_str(&text)?;

            if let Some(params) = value.get("params") {
                let status = &params["result"];
                println!("Status: {}", status);

                // Check for finalization
                if let Some(hash) = status.get("finalized") {
                    println!("Finalized in block: {}", hash);
                    break;
                }

                // Check for terminal failure states
                if status == "dropped" || status == "invalid" {
                    eprintln!("Transaction failed: {}", status);
                    break;
                }
            } else if let Some(error) = value.get("error") {
                eprintln!("Submission error: {}", error["message"]);
                break;
            } else {
                println!("Subscription ID: {}", value["result"]);
            }
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Transaction Confirmation with Timeout

Wait for finalization with a configurable timeout to avoid hanging indefinitely:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function sendAndConfirm(api, sender, tx, timeoutMs = 120000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('Transaction confirmation timed out'));
    }, timeoutMs);

    tx.signAndSend(sender, ({ status, dispatchError, events }) => {
      if (dispatchError) {
        clearTimeout(timer);
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${section}.${name}: ${docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        clearTimeout(timer);
        resolve({
          blockHash: status.asFinalized.toHex(),
          events: events.map((e) => `${e.event.section}.${e.event.method}`)
        });
      }
    }).catch((err) => {
      clearTimeout(timer);
      reject(err);
    });
  });
}
```

### 2. Batch Transaction Pipeline

Submit multiple extrinsics sequentially and track each one through finalization:

```javascript
async function submitBatch(api, sender, calls) {
  const results = [];
  let nonce = (await api.rpc.system.accountNextIndex(sender.address)).toNumber();

  for (const call of calls) {
    const result = await new Promise((resolve, reject) => {
      call.signAndSend(sender, { nonce: nonce++ }, ({ status, dispatchError }) => {
        if (dispatchError) {
          const decoded = dispatchError.isModule
            ? api.registry.findMetaError(dispatchError.asModule)
            : { name: dispatchError.toString() };
          reject(new Error(`Dispatch error: ${decoded.name}`));
        }

        if (status.isFinalized) {
          resolve({ blockHash: status.asFinalized.toHex(), nonce: nonce - 1 });
        }
      });
    });
    results.push(result);
    console.log(`Tx nonce=${result.nonce} finalized in ${result.blockHash}`);
  }

  return results;
}
```

### 3. Reorg-Aware Event Handling

Handle block retractions gracefully, re-evaluating transaction inclusion after reorganizations:

```javascript
async function sendWithReorgHandling(api, sender, tx) {
  let includedBlock = null;

  return new Promise((resolve, reject) => {
    tx.signAndSend(sender, ({ status, events }) => {
      if (status.isReady) {
        console.log('Transaction in ready queue');
      }

      if (status.isInBlock) {
        includedBlock = status.asInBlock.toHex();
        console.log(`Included in block: ${includedBlock}`);
      }

      if (status.isRetracted) {
        console.warn(`Block retracted: ${status.asRetracted.toHex()} -- waiting for re-inclusion`);
        includedBlock = null;
      }

      if (status.isFinalized) {
        console.log(`Finalized in block: ${status.asFinalized.toHex()}`);
        resolve({ finalized: status.asFinalized.toHex(), events });
      }

      if (status.isDropped || status.isInvalid) {
        reject(new Error(`Transaction ${status.type}`));
      }

      if (status.isUsurped) {
        reject(new Error(`Transaction usurped by ${status.asUsurped.toHex()}`));
      }
    });
  });
}
```

## Status Flow

```
              ┌─────────────────────────────────────┐
              │          future (nonce gap)          │
              └──────────────┬──────────────────────┘
                             │ nonce becomes current
                             ▼
 submit ──► ready ──► broadcast ──► inBlock ──► finalized ✓
              │                       │
              ├──► dropped ✗          ├──► retracted (reorg) ──► inBlock (re-included)
              ├──► invalid ✗          └──► finalityTimeout ✗
              └──► usurped ✗
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/xx-network/author_submitExtrinsic) -- Submit an extrinsic without subscribing to status updates (fire-and-forget)
- `system_accountNextIndex` -- Get the next valid nonce for an account, including pending pool transactions
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/xx-network/author_pendingExtrinsics) -- List all extrinsics currently in the transaction pool
- [`payment_queryInfo`](https://www.dwellir.com/docs/xx-network/payment_queryInfo) -- Estimate the fee for an extrinsic before submission
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/chain_getFinalizedHead) -- Get the hash of the latest finalized block

---

## author_submitExtrinsic - XX Network RPC Method

# author_submitExtrinsic - XX Network RPC Method

Submits a fully signed extrinsic to XX Network for inclusion in a future block. The extrinsic enters the transaction pool and is propagated to other nodes. This is the primary method for broadcasting any on-chain operation, including balance transfers, staking, governance, and pallet interactions.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`author_submitExtrinsic` is essential for XX Network developers building privacy-preserving applications:

- **Token Transfers** -- Send native tokens or assets between accounts on XX Network
- **Staking and Governance** -- Submit staking nominations, validator operations, and governance votes for secure messaging, private payments, and quantum-resistant cryptography
- **Smart Contract Interaction** -- Call ink! or EVM smart contracts deployed on the chain
- **Automated Systems** -- Build bots, keepers, and automated transaction pipelines that submit extrinsics programmatically

## Best Practices

- Sign extrinsics client-side before submission -- never expose private keys to the node
- Returns the transaction hash immediately after submission -- polling is required for confirmation
- Monitor inclusion via `chain_getBlock` or subscribe to `chain_subscribeNewHeads`
- Equivalent to `eth_sendRawTransaction` on EVM chains

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-encoded signed extrinsic including signature, nonce, era, and tip

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_submitExtrinsic",
  "params": ["0x4d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The extrinsic hash (Blake2-256) as a hex string, used to track the transaction

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
```

## Error Responses

### Error Response (invalid transaction)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction has a bad signature"
  }
}
```

### Error Response (nonce too low)

- Code: `1010`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 1010,
    "message": "Invalid Transaction",
    "data": "Transaction is outdated"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_submitExtrinsic",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Set up sender keypair
const keyring = new Keyring({ type: 'sr25519' });
const sender = keyring.addFromUri('//Alice'); // Use your actual key in production

// Build and send a transfer
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Adjust for chain decimals

const hash = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender);

console.log('Transaction hash:', hash.toHex());

// With status tracking
const unsub = await api.tx.balances
  .transferKeepAlive(recipient, amount)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    if (status.isInBlock) {
      console.log(`Included in block: ${status.asInBlock.toHex()}`);
    }
    if (status.isFinalized) {
      console.log(`Finalized in block: ${status.asFinalized.toHex()}`);

      if (dispatchError) {
        if (dispatchError.isModule) {
          const { docs, name, section } = api.registry.findMetaError(
            dispatchError.asModule
          );
          console.error(`Error: ${section}.${name}: ${docs.join(' ')}`);
        } else {
          console.error('Error:', dispatchError.toString());
        }
      } else {
        console.log('Transaction succeeded');
      }

      unsub();
    }
  });

// Low-level: submit a pre-signed extrinsic
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'author_submitExtrinsic',
    params: ['0x4d0284ff...'], // pre-signed extrinsic hex
    id: 1
  })
});

const { result, error } = await response.json();
if (error) {
  console.error('Submission failed:', error.message, error.data);
} else {
  console.log('Extrinsic hash:', result);
}
```

```python
import requests

def submit_extrinsic(extrinsic_hex):
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'author_submitExtrinsic',
            'params': [extrinsic_hex],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f"Submission failed: {result['error']}")
    return result['result']

# Using substrate-interface (recommended)
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')

# Create keypair
keypair = Keypair.create_from_uri('//Alice')  # Use your actual key

# Compose a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create, sign, and submit extrinsic
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)

print(f'Extrinsic hash: {receipt.extrinsic_hash}')
print(f'Block hash: {receipt.block_hash}')
print(f'Success: {receipt.is_success}')

if not receipt.is_success:
    print(f'Error: {receipt.error_message}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Submit a pre-signed extrinsic
    let extrinsic_hex = "0x4d0284ff..."; // Build with subxt or offline signer

    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "author_submitExtrinsic",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    if let Some(error) = result.get("error") {
        eprintln!("Submission failed: {} - {}",
            error["message"],
            error.get("data").unwrap_or(&json!(""))
        );
    } else {
        println!("Extrinsic hash: {}", result["result"]);
    }

    Ok(())
}

// For full signing and submission in Rust, use the `subxt` crate:
// https://github.com/paritytech/subxt
//
// use subxt::{OnlineClient, PolkadotConfig};
// use subxt_signer::sr25519::dev;
//
// let api = OnlineClient::<PolkadotConfig>::from_url("https://api-xxnetwork.dwellir.com/YOUR_API_KEY").await?;
// let dest = dev::bob().public_key().into();
// let tx = polkadot::tx().balances().transfer_keep_alive(dest, 1_000_000_000_000);
// let hash = api.tx().sign_and_submit_default(&tx, &dev::alice()).await?;
```

## Common Use Cases

### 1. Transfer with Fee Pre-Check

Verify fees and balance before submitting a transfer:

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

async function safeTransfer(api, sender, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

  // Step 1: Estimate fee
  const info = await transfer.paymentInfo(sender.address);
  const fee = info.partialFee.toBigInt();
  console.log(`Estimated fee: ${info.partialFee.toHuman()}`);

  // Step 2: Check balance
  const account = await api.query.system.account(sender.address);
  const free = account.data.free.toBigInt();
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const totalCost = BigInt(amount) + fee;

  if (free - totalCost < existentialDeposit) {
    throw new Error(`Insufficient balance. Need ${totalCost}, have ${free}`);
  }

  // Step 3: Submit
  const hash = await transfer.signAndSend(sender);
  console.log(`Submitted: ${hash.toHex()}`);
  return hash;
}
```

### 2. Batch Transaction Submission

Submit multiple operations in a single extrinsic:

```javascript
async function submitBatch(api, sender, calls) {
  const batch = api.tx.utility.batchAll(calls);

  // Estimate total fee
  const info = await batch.paymentInfo(sender.address);
  console.log(`Batch fee: ${info.partialFee.toHuman()} for ${calls.length} calls`);

  // Submit with event tracking
  return new Promise((resolve, reject) => {
    batch.signAndSend(sender, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        if (dispatchError.isModule) {
          const decoded = api.registry.findMetaError(dispatchError.asModule);
          reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
        } else {
          reject(new Error(dispatchError.toString()));
        }
      }

      if (status.isFinalized) {
        const successEvents = events.filter(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        resolve({
          blockHash: status.asFinalized.toHex(),
          success: successEvents.length > 0,
          events: events.length
        });
      }
    });
  });
}

// Usage: batch multiple transfers
const calls = [
  api.tx.balances.transferKeepAlive(recipient1, amount1),
  api.tx.balances.transferKeepAlive(recipient2, amount2),
  api.tx.balances.transferKeepAlive(recipient3, amount3)
];

const result = await submitBatch(api, sender, calls);
```

### 3. Nonce Management for Sequential Transactions

Submit multiple transactions in rapid succession with correct nonce handling:

```javascript
async function submitSequential(api, sender, extrinsics) {
  // Get the starting nonce
  let nonce = await api.rpc.system.accountNextIndex(sender.address);

  const hashes = [];
  for (const ext of extrinsics) {
    const hash = await ext.signAndSend(sender, { nonce });
    hashes.push(hash.toHex());
    console.log(`Submitted with nonce ${nonce}: ${hash.toHex()}`);
    nonce = nonce.addn(1);
  }

  return hashes;
}
```

## Related Methods

- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/xx-network/author_pendingExtrinsics) -- Check the transaction pool for pending extrinsics
- [`payment_queryInfo`](https://www.dwellir.com/docs/xx-network/payment_queryInfo) -- Estimate fees before submitting
- `system_accountNextIndex` -- Get the next valid nonce for an account
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) -- Call runtime APIs (e.g., for nonce via `AccountNonceApi`)
- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) -- Verify extrinsic inclusion in a block

---

## beefy_getFinalizedHead - XX Network RPC Method

# beefy_getFinalizedHead - XX Network RPC Method

Returns the block hash of the latest BEEFY-finalized block on XX Network. BEEFY (Bridge Efficiency Enabling Finality Yielder) provides additional finality proofs that are optimized for light clients and cross-chain bridges, using compact aggregated signatures instead of full GRANDPA justifications.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`beefy_getFinalizedHead` is important for XX Network developers building privacy-preserving applications:

- **Cross-Chain Bridges** - Verify finality proofs efficiently for bridge operations on secure messaging, private payments, and quantum-resistant cryptography
- **Light Clients** - Verify finality without downloading full GRANDPA justifications
- **Trustless Bridges** - Generate compact finality proofs that can be verified on external chains
- **Bridge Monitoring** - Track BEEFY finality progress relative to GRANDPA finality

## Best Practices

- BEEFY (Bridge Efficiency Enabling Finality Yielder) protocol secures cross-chain bridge finality
- Returns the hash of the latest BEEFY-finalized block for proof generation
- Use for cross-chain verification rather than regular block finality (use `chain_getFinalizedHead` for that)
- Required for bridge relayers that verify finality across connected chains

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "beefy_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest BEEFY-finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response (BEEFY Not Enabled)

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "BEEFY is not enabled on this chain"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "beefy_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  // Get BEEFY finalized head
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  console.log('BEEFY finalized:', beefyHead.toHex());

  // Compare with GRANDPA finalized
  const grandpaHead = await api.rpc.chain.getFinalizedHead();
  console.log('GRANDPA finalized:', grandpaHead.toHex());

  // Get block numbers for comparison
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const grandpaBlock = await api.rpc.chain.getBlock(grandpaHead);

  const beefyNum = beefyBlock.block.header.number.toNumber();
  const grandpaNum = grandpaBlock.block.header.number.toNumber();
  console.log(`BEEFY lag behind GRANDPA: ${grandpaNum - beefyNum} blocks`);
} catch (error) {
  console.error('BEEFY may not be enabled:', error.message);
}

await api.disconnect();
```

```python
import requests

def get_beefy_finalized_head():
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'beefy_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"BEEFY error: {result['error']['message']}")

    return result['result']

def get_grandpa_finalized_head():
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 2
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

try:
    beefy_hash = get_beefy_finalized_head()
    grandpa_hash = get_grandpa_finalized_head()
    print(f'BEEFY finalized: {beefy_hash}')
    print(f'GRANDPA finalized: {grandpa_hash}')
except Exception as e:
    print(f'Error: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Call beefy_getFinalizedHead via raw RPC
    let beefy_head: Value = api.rpc()
        .request("beefy_getFinalizedHead", subxt::rpc_params![])
        .await?;

    println!("BEEFY finalized: {}", beefy_head);

    // Compare with GRANDPA finalized
    let grandpa_head = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("GRANDPA finalized: {:?}", grandpa_head);

    Ok(())
}
```

## Common Use Cases

### 1. Bridge Finality Verification

Verify BEEFY finality before relaying messages on a cross-chain bridge:

```javascript
async function verifyBridgeFinality(api, targetBlockHash) {
  const beefyHead = await api.rpc.beefy.getFinalizedHead();
  const beefyBlock = await api.rpc.chain.getBlock(beefyHead);
  const beefyNumber = beefyBlock.block.header.number.toNumber();

  const targetBlock = await api.rpc.chain.getBlock(targetBlockHash);
  const targetNumber = targetBlock.block.header.number.toNumber();

  if (beefyNumber >= targetNumber) {
    console.log(`Block #${targetNumber} has BEEFY finality - safe to relay`);
    return true;
  } else {
    console.log(`Waiting: BEEFY at #${beefyNumber}, target at #${targetNumber}`);
    return false;
  }
}
```

### 2. BEEFY vs GRANDPA Finality Monitor

Track the gap between the two finality gadgets:

```javascript
async function monitorFinalityGadgets(api) {
  setInterval(async () => {
    try {
      const [beefyHead, grandpaHead] = await Promise.all([
        api.rpc.beefy.getFinalizedHead(),
        api.rpc.chain.getFinalizedHead()
      ]);

      const [beefyBlock, grandpaBlock] = await Promise.all([
        api.rpc.chain.getBlock(beefyHead),
        api.rpc.chain.getBlock(grandpaHead)
      ]);

      const beefyNum = beefyBlock.block.header.number.toNumber();
      const grandpaNum = grandpaBlock.block.header.number.toNumber();
      const lag = grandpaNum - beefyNum;

      console.log(`GRANDPA: #${grandpaNum} | BEEFY: #${beefyNum} | Lag: ${lag} blocks`);
    } catch (error) {
      console.error('Monitor error:', error.message);
    }
  }, 12000);
}
```

## BEEFY vs GRANDPA Finality

| Aspect                | GRANDPA                                | BEEFY                                      |
| --------------------- | -------------------------------------- | ------------------------------------------ |
| **Purpose**           | Primary chain finality                 | Bridge-optimized finality                  |
| **Proof Size**        | Larger (full validator set signatures) | Compact (aggregated BLS signatures)        |
| **Latency**           | Immediate after supermajority          | Slightly delayed behind GRANDPA            |
| **Verification Cost** | Higher on external chains              | Lower - designed for on-chain verification |
| **Use Case**          | On-chain consensus finality            | Cross-chain bridges and light clients      |

## Availability

BEEFY is enabled on Polkadot and Kusama relay chains and some parachains. If BEEFY is not active on the chain you are querying, this method will return an error. Check chain documentation or try calling the method to confirm availability.

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/chain_getFinalizedHead) - Get GRANDPA finalized head
- [`grandpa_roundState`](https://www.dwellir.com/docs/xx-network/grandpa_roundState) - Monitor GRANDPA consensus state
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeFinalizedHeads) - Subscribe to GRANDPA finalized blocks

---

## chain_getBlock - XX Network RPC Method

# chain_getBlock - XX Network RPC Method

Retrieves complete block information from XX Network, including the block header, extrinsics, and justifications.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## Use Cases

The `chain_getBlock` method is essential for:

- **Block explorers** - Display complete block information
- **Chain analysis** - Analyze block production patterns
- **Transaction verification** - Confirm extrinsic inclusion for secure messaging, private payments, and quantum-resistant cryptography
- **Data indexing** - Build historical blockchain databases

## Best Practices

- Cache block data by hash -- blocks are immutable once finalized on Substrate chains
- Use `chain_getBlockHash` first to resolve block number to hash before calling this method
- Handle `null` results gracefully for non-existent blocks
- Combine with `chain_getFinalizedHead` for consensus-safe block retrieval

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlock",
  "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
  "id": 1
}
```

## Response Fields

- `block` (`Object, required`): Complete block data
- `block.header` (`Object, required`): Block header information
- `block.header.parentHash` (`String, required`): Hash of the parent block
- `block.header.number` (`String, required`): Block number (hex-encoded)
- `block.header.stateRoot` (`String, required`): Root of the state trie
- `block.header.extrinsicsRoot` (`String, required`): Root of the extrinsics trie
- `block.extrinsics` (`Array, required`): Array of extrinsics in the block
- `justifications` (`Array, required`): Block justifications (if available)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "block": {},
    "block.header": {},
    "block.header.parentHash": "<value>",
    "block.header.number": "<value>",
    "block.header.stateRoot": "<value>",
    "block.header.extrinsicsRoot": "<value>",
    "block.extrinsics": [],
    "justifications": []
  }
}
```

## Code Examples

cURL
JavaScript
Python

```bash
# Get latest block
curl https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": [],
    "id": 1
  }'

# Get specific block
curl https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlock",
    "params": ["0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest block
const latestHash = await api.rpc.chain.getBlockHash();
const latestBlock = await api.rpc.chain.getBlock(latestHash);

console.log('Latest block:', {
  number: latestBlock.block.header.number.toNumber(),
  hash: latestHash.toHex(),
  extrinsicsCount: latestBlock.block.extrinsics.length
});

// Get specific block
const blockHash = '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
const block = await api.rpc.chain.getBlock(blockHash);
console.log('Block extrinsics:', block.block.extrinsics.length);

await api.disconnect();
```

```python
import requests
import json

def get_block(block_hash=None):
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlock',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    data = response.json()

    if 'error' in data:
        raise Exception(f"RPC Error: {data['error']}")

    return data['result']

# Get latest block
latest_block = get_block()
block_number = int(latest_block['block']['header']['number'], 16)
print(f'Latest block number: {block_number}')

# Get specific block
specific_block = get_block('0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3')
print(f"Extrinsics count: {len(specific_block['block']['extrinsics'])}")
```

## Related Methods

- [`chain_getBlockHash`](https://www.dwellir.com/docs/xx-network/chain_getBlockHash) - Get block hash by number
- [`chain_getHeader`](https://www.dwellir.com/docs/xx-network/chain_getHeader) - Get block header only
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/chain_getFinalizedHead) - Get finalized block hash

---

## chain_getBlockHash - XX Network RPC Method

# chain_getBlockHash - XX Network RPC Method

Returns the block hash for a given block number on XX Network. This is the primary method for converting block numbers into block hashes, which are required by most other chain RPC methods.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`chain_getBlockHash` is fundamental for XX Network developers building privacy-preserving applications:

- **Historical Queries** - Convert block numbers to hashes for state queries at specific heights on XX Network
- **Block Navigation** - Navigate the blockchain history for secure messaging, private payments, and quantum-resistant cryptography
- **Data Indexing** - Build block number-to-hash mappings for indexers and explorers
- **Cross-Reference** - Translate block numbers from events or logs into hashes for detailed lookups

## Best Practices

- Use before `chain_getBlock` if you need hash-based block lookup on XX Network
- Block numbers may change during chain reorganizations -- hashes are immutable
- Returns `null` for future blocks that do not exist yet
- Cache the genesis block hash as a known reference point

## Request Parameters

- `blockNumber` (`Number, optional`): Block number to look up. If omitted, returns the hash of the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getBlockHash",
  "params": [1000000],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte block hash, or null if block number does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block number"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get hash for a specific block number
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [1000000],
    "id": 1
  }'

# Get hash for the latest block
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getBlockHash",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get hash for specific block number
const blockNumber = 1000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log(`Block ${blockNumber} hash:`, blockHash.toHex());

// Get hash for latest block
const latestHash = await api.rpc.chain.getBlockHash();
console.log('Latest block hash:', latestHash.toHex());

// Get genesis block hash
const genesisHash = await api.rpc.chain.getBlockHash(0);
console.log('Genesis hash:', genesisHash.toHex());

await api.disconnect();
```

```python
import requests

def get_block_hash(block_number=None):
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'
    params = [block_number] if block_number is not None else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getBlockHash',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get specific block hash
block_hash = get_block_hash(1000000)
print(f'Block 1000000 hash: {block_hash}')

# Get latest block hash
latest_hash = get_block_hash()
print(f'Latest block hash: {latest_hash}')

# Get genesis hash
genesis_hash = get_block_hash(0)
print(f'Genesis hash: {genesis_hash}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get hash for a specific block number
    let block_hash = api.rpc()
        .chain_get_block_hash(Some(1_000_000u32.into()))
        .await?;

    println!("Block 1000000 hash: {:?}", block_hash);

    // Get latest block hash
    let latest_hash = api.rpc()
        .chain_get_block_hash(None)
        .await?;

    println!("Latest block hash: {:?}", latest_hash);

    Ok(())
}
```

## Common Use Cases

### 1. Block Range Iterator

Iterate over a range of blocks on XX Network for indexing:

```javascript
async function iterateBlocks(api, startBlock, endBlock) {
  for (let num = startBlock; num <= endBlock; num++) {
    const hash = await api.rpc.chain.getBlockHash(num);
    const block = await api.rpc.chain.getBlock(hash);

    console.log(`Block #${num}: ${block.block.extrinsics.length} extrinsics`);
  }
}
```

### 2. Historical State Query

Query XX Network state at a specific block height:

```javascript
async function getBalanceAtBlock(api, address, blockNumber) {
  const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
  const apiAt = await api.at(blockHash);
  const account = await apiAt.query.system.account(address);

  return {
    blockNumber,
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString()
  };
}
```

### 3. Genesis Hash Verification

Verify you are connected to the correct XX Network network:

```javascript
async function verifyNetwork(api, expectedGenesisHash) {
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  if (genesisHash.toHex() !== expectedGenesisHash) {
    throw new Error(`Wrong network! Expected ${expectedGenesisHash}, got ${genesisHash.toHex()}`);
  }

  console.log('Connected to correct network');
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) - Get full block data by hash
- [`chain_getHeader`](https://www.dwellir.com/docs/xx-network/chain_getHeader) - Get block header by hash
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/chain_getFinalizedHead) - Get the latest finalized block hash

---

## chain_getFinalizedHead - XX Network RPC Method

# chain_getFinalizedHead - XX Network RPC Method

Returns the hash of the last finalized block on XX Network. Finalized blocks have been confirmed by the GRANDPA finality gadget and are guaranteed to never be reverted.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`chain_getFinalizedHead` is critical for XX Network developers building privacy-preserving applications:

- **Exchange Deposits** - Only credit user funds after the block has been finalized on XX Network
- **Transaction Confirmation** - Verify transactions have achieved irreversible finality for secure messaging, private payments, and quantum-resistant cryptography
- **Safe Checkpoints** - Use finalized blocks as safe anchors for indexing and state queries
- **Bridge Operations** - Confirm source-chain finality before executing cross-chain transfers

## Best Practices

- Finalized blocks are irreversible and safe for all consensus-critical operations
- Use lower polling frequency than new heads -- finalization is slower
- Combine with `chain_getBlock` for full block data on finalized blocks
- For bridge applications, use `beefy_getFinalizedHead` for cross-chain proofs

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getFinalizedHead",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Hash, required`): Hex-encoded 32-byte hash of the latest finalized block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5d83f9a0c22ef15a5e4e8b7f7b3b0c3a1d6e9f2a4b7c8d0e1f2a3b4c5d6e7f80"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getFinalizedHead",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get finalized block hash
const finalizedHash = await api.rpc.chain.getFinalizedHead();
console.log('Finalized block hash:', finalizedHash.toHex());

// Get finalized block details
const block = await api.rpc.chain.getBlock(finalizedHash);
const blockNumber = block.block.header.number.toNumber();
console.log('Finalized block number:', blockNumber);

// Compare with best block to see finality lag
const bestHeader = await api.rpc.chain.getHeader();
const lag = bestHeader.number.toNumber() - blockNumber;
console.log(`Finality lag: ${lag} blocks`);

await api.disconnect();
```

```python
import requests

def get_finalized_head():
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getFinalizedHead',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

finalized_hash = get_finalized_head()
print(f'Finalized block hash: {finalized_hash}')

# Fetch finalized block details
payload = {
    'jsonrpc': '2.0',
    'method': 'chain_getBlock',
    'params': [finalized_hash],
    'id': 2
}

response = requests.post('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', json=payload)
block = response.json()['result']
block_number = int(block['block']['header']['number'], 16)
print(f'Finalized block number: {block_number}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    let finalized_hash = api.rpc()
        .chain_get_finalized_head()
        .await?;

    println!("Finalized block hash: {:?}", finalized_hash);

    let block = api.rpc()
        .chain_get_block(Some(finalized_hash))
        .await?
        .expect("Finalized block should exist");

    println!("Finalized block number: {}", block.block.header.number);

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Confirmation

Wait for finality before crediting deposits on XX Network:

```javascript
async function waitForFinality(api, txBlockHash) {
  return new Promise((resolve) => {
    const unsub = api.rpc.chain.subscribeFinalizedHeads(async (header) => {
      const finalizedHash = await api.rpc.chain.getBlockHash(header.number);

      // Check if the transaction block has been finalized
      const finalizedNumber = header.number.toNumber();
      const txBlock = await api.rpc.chain.getBlock(txBlockHash);
      const txNumber = txBlock.block.header.number.toNumber();

      if (finalizedNumber >= txNumber) {
        console.log(`Transaction finalized at block #${txNumber}`);
        unsub();
        resolve(txBlockHash);
      }
    });
  });
}
```

### 2. Safe State Queries

Query chain state at the finalized block to avoid reading data that could be reverted:

```javascript
async function getSafeBalance(api, address) {
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const apiAt = await api.at(finalizedHash);
  const account = await apiAt.query.system.account(address);

  return {
    free: account.data.free.toString(),
    reserved: account.data.reserved.toString(),
    finalizedAt: finalizedHash.toHex()
  };
}
```

### 3. Finality Lag Monitor

Track the gap between best and finalized blocks for health monitoring:

```javascript
async function monitorFinalityLag(api, threshold = 10) {
  const bestHeader = await api.rpc.chain.getHeader();
  const finalizedHash = await api.rpc.chain.getFinalizedHead();
  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);

  const lag = bestHeader.number.toNumber() - finalizedHeader.number.toNumber();
  console.log(`Finality lag: ${lag} blocks`);

  if (lag > threshold) {
    console.warn(`WARNING: Finality lag (${lag}) exceeds threshold (${threshold})`);
  }

  return lag;
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) - Get full block data by hash
- [`chain_getBlockHash`](https://www.dwellir.com/docs/xx-network/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers
- [`grandpa_roundState`](https://www.dwellir.com/docs/xx-network/grandpa_roundState) - Monitor GRANDPA finality progress

---

## chain_getHeader - XX Network RPC Method

# chain_getHeader - XX Network RPC Method

Returns the block header for a given hash on XX Network. This is a lightweight alternative to `chain_getBlock` when you only need header metadata without extrinsic data.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`chain_getHeader` is ideal for XX Network developers building privacy-preserving applications:

- **Lightweight Queries** - Get block metadata without downloading full extrinsic data on XX Network
- **Chain Synchronization** - Track block production and monitor chain progress for secure messaging, private payments, and quantum-resistant cryptography
- **Parent Chain Navigation** - Follow `parentHash` links to traverse the chain backwards
- **State Verification** - Use `stateRoot` and `extrinsicsRoot` for Merkle proof verification

## Best Practices

- Headers are much smaller than full blocks -- use for quick verification without body data
- The `parentHash` field verifies chain continuity by linking to the previous block
- Digest logs contain consensus messages and seal data
- Cache headers for recent blocks to reduce repeated API calls

## Request Parameters

- `blockHash` (`String, optional`): Hex-encoded block hash. If omitted, returns the latest block header

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_getHeader",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Hash of the parent block
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): Merkle root of the state trie after this block
- `extrinsicsRoot` (`Hash, required`): Merkle root of the extrinsics trie
- `digest` (`Digest, required`): Block digest containing consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "parentHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
    "number": "0xf4240",
    "stateRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "extrinsicsRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
    "digest": {
      "logs": [
        "0x0642414245b50103..."
      ]
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid block hash"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get latest block header
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": [],
    "id": 1
  }'

# Get header for a specific block hash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "chain_getHeader",
    "params": ["0xYOUR_RECENT_BLOCK_HASH"],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get latest header
const header = await api.rpc.chain.getHeader();
console.log('Block number:', header.number.toNumber());
console.log('Parent hash:', header.parentHash.toHex());
console.log('State root:', header.stateRoot.toHex());
console.log('Extrinsics root:', header.extrinsicsRoot.toHex());

// Get header for a specific block hash
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalHeader = await api.rpc.chain.getHeader(blockHash);
console.log('Block #1000000 parent:', historicalHeader.parentHash.toHex());

await api.disconnect();
```

```python
import requests

def get_header(block_hash=None):
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'chain_getHeader',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

# Get latest header
header = get_header()
block_number = int(header['number'], 16)
print(f'Block number: {block_number}')
print(f"Parent hash: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
print(f"Extrinsics root: {header['extrinsicsRoot']}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    // Get latest header
    let header = api.rpc()
        .chain_get_header(None)
        .await?
        .expect("Header should exist");

    println!("Block number: {}", header.number);
    println!("Parent hash: {:?}", header.parent_hash);
    println!("State root: {:?}", header.state_root);

    Ok(())
}
```

## Common Use Cases

### 1. Block Time Calculator

Estimate block production rate on XX Network:

```javascript
async function estimateBlockTime(api, sampleSize = 10) {
  const latestHeader = await api.rpc.chain.getHeader();
  const latestNumber = latestHeader.number.toNumber();

  const oldHash = await api.rpc.chain.getBlockHash(latestNumber - sampleSize);
  const oldHeader = await api.rpc.chain.getHeader(oldHash);

  // Use timestamp from block digests or timestamp pallet
  const latestTimestamp = await api.query.timestamp.now();
  const apiAt = await api.at(oldHash);
  const oldTimestamp = await apiAt.query.timestamp.now();

  const timeDiff = latestTimestamp.toNumber() - oldTimestamp.toNumber();
  const avgBlockTime = timeDiff / sampleSize;

  console.log(`Average block time: ${avgBlockTime / 1000}s over ${sampleSize} blocks`);
  return avgBlockTime;
}
```

### 2. Chain Traversal

Walk backwards through the XX Network chain using parent hashes:

```javascript
async function walkChain(api, startHash, depth = 5) {
  let currentHash = startHash || (await api.rpc.chain.getBlockHash());
  const headers = [];

  for (let i = 0; i < depth; i++) {
    const header = await api.rpc.chain.getHeader(currentHash);
    headers.push({
      number: header.number.toNumber(),
      hash: currentHash.toString(),
      parentHash: header.parentHash.toHex()
    });
    currentHash = header.parentHash;
  }

  return headers;
}
```

### 3. Lightweight Block Monitor

Monitor XX Network block production without downloading full blocks:

```javascript
async function monitorBlocks(api, callback) {
  let lastNumber = 0;

  setInterval(async () => {
    const header = await api.rpc.chain.getHeader();
    const number = header.number.toNumber();

    if (number > lastNumber) {
      console.log(`New block #${number}`);
      callback(header);
      lastNumber = number;
    }
  }, 3000);
}
```

## Related Methods

- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) - Get full block with extrinsics
- [`chain_getBlockHash`](https://www.dwellir.com/docs/xx-network/chain_getBlockHash) - Get block hash by number
- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeNewHeads) - Subscribe to new block headers in real time
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeFinalizedHeads) - Subscribe to finalized block headers

---

## chain_subscribeFinalizedHeads - XX Network RPC Method

# chain_subscribeFinalizedHeads - XX Network RPC Method

Subscribe to receive notifications when blocks are finalized on XX Network. Finalized blocks are guaranteed to never be reverted by the GRANDPA finality gadget, making this the safest way to track confirmed state changes.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`chain_subscribeFinalizedHeads` is critical for XX Network developers building privacy-preserving applications:

- **Exchange Deposits** - Only credit funds after finalization for secure messaging, private payments, and quantum-resistant cryptography
- **Bridge Operations** - Wait for finality before executing cross-chain transfers
- **Critical State Changes** - Ensure irreversibility before acting on important transactions
- **Compliance Workflows** - Record-keeping that requires provably irreversible state

## Best Practices

- Requires a WebSocket connection at `wss://api-xxnetwork.dwellir.com/YOUR_API_KEY`
- Finalized headers are irreversible and safe for bridge relay operations
- Notification frequency is lower than `chain_subscribeNewHeads`
- Unsubscribe when done to free connection resources

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-xxnetwork.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeFinalizedHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to finalized heads
const unsubscribe = await api.rpc.chain.subscribeFinalizedHeads((header) => {
  console.log(`Finalized block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_finalized():
    uri = 'wss://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeFinalizedHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for finalized headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f'Finalized: #{block_num}')
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_finalized())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut finalized_heads = api.rpc()
        .subscribe_finalized_block_headers()
        .await?;

    while let Some(Ok(header)) = finalized_heads.next().await {
        println!(
            "Finalized block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Exchange Deposit Watcher

Watch for finalized transfers and credit user accounts on XX Network:

```javascript
async function watchDeposits(api, depositAddresses) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const blockHash = header.hash;
    const block = await api.rpc.chain.getBlock(blockHash);
    const apiAt = await api.at(blockHash);
    const events = await apiAt.query.system.events();

    // Check for transfer events in the finalized block
    events.forEach((record) => {
      const { event } = record;
      if (event.section === 'balances' && event.method === 'Transfer') {
        const [from, to, amount] = event.data;
        if (depositAddresses.includes(to.toString())) {
          console.log(`Finalized deposit: ${amount} from ${from} to ${to}`);
          // Credit user account - this block will never be reverted
        }
      }
    });
  });

  return unsub;
}
```

### 2. Finality Lag Tracker

Monitor the gap between best and finalized blocks:

```javascript
async function trackFinalityLag(api) {
  let bestNumber = 0;

  api.rpc.chain.subscribeNewHeads((header) => {
    bestNumber = header.number.toNumber();
  });

  api.rpc.chain.subscribeFinalizedHeads((header) => {
    const finalizedNumber = header.number.toNumber();
    const lag = bestNumber - finalizedNumber;

    console.log(`Best: #${bestNumber} | Finalized: #${finalizedNumber} | Lag: ${lag} blocks`);

    if (lag > 10) {
      console.warn('WARNING: High finality lag detected - GRANDPA may be stalling');
    }
  });
}
```

### 3. Cross-Chain Bridge Relay

Relay finalized headers to a bridge contract:

```javascript
async function relayFinalizedHeaders(api, bridgeContract) {
  const unsub = await api.rpc.chain.subscribeFinalizedHeads(async (header) => {
    const headerData = {
      number: header.number.toNumber(),
      stateRoot: header.stateRoot.toHex(),
      extrinsicsRoot: header.extrinsicsRoot.toHex(),
      parentHash: header.parentHash.toHex()
    };

    console.log(`Relaying finalized header #${headerData.number}`);
    await bridgeContract.submitHeader(headerData);
  });

  return unsub;
}
```

## Finality Lag

Finalized blocks typically lag behind the best block by a few blocks due to GRANDPA consensus requirements. This lag is normal and ensures Byzantine fault tolerance. The typical lag is 2-3 blocks under healthy network conditions.

## Related Methods

- [`chain_subscribeNewHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeNewHeads) - Subscribe to all new blocks (not just finalized)
- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/chain_getFinalizedHead) - Get current finalized block hash (one-shot)
- [`grandpa_roundState`](https://www.dwellir.com/docs/xx-network/grandpa_roundState) - Monitor GRANDPA consensus progress
- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) - Get full block data for a finalized hash

---

## chain_subscribeNewHeads - XX Network RPC Method

# chain_subscribeNewHeads - XX Network RPC Method

Subscribe to receive notifications when new block headers are produced on XX Network. This WebSocket subscription provides real-time, push-based updates for each new block, making it more efficient than polling.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`chain_subscribeNewHeads` is essential for XX Network developers building privacy-preserving applications:

- **Block Monitoring** - Track new blocks in real time on XX Network for secure messaging, private payments, and quantum-resistant cryptography
- **Event Indexing** - Trigger processing pipelines when new blocks arrive
- **Chain Synchronization** - Keep external databases and systems in sync with the chain
- **Dashboard Updates** - Push live block data to monitoring dashboards

## Best Practices

- Requires a WebSocket connection at `wss://api-xxnetwork.dwellir.com/YOUR_API_KEY`
- Unsubscribe when monitoring is no longer needed to free node resources
- Headers arrive faster than full blocks -- use `chain_getBlock` for full data when needed
- For consensus-critical applications, prefer `chain_subscribeFinalizedHeads`

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}
```

## Response Fields

- `parentHash` (`Hash, required`): Parent block hash
- `number` (`BlockNumber, required`): Block number (hex-encoded)
- `stateRoot` (`Hash, required`): State trie root hash after this block
- `extrinsicsRoot` (`Hash, required`): Extrinsics trie root hash
- `digest` (`Digest, required`): Block digest with consensus engine logs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "subscription_id_here"
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# WebSocket subscription (requires wscat or similar tool)
wscat -c wss://api-xxnetwork.dwellir.com/YOUR_API_KEY -x '{
  "jsonrpc": "2.0",
  "method": "chain_subscribeNewHeads",
  "params": [],
  "id": 1
}'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Subscribe to new heads
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
  console.log(`New block #${header.number}`);
  console.log(`  Hash: ${header.hash.toHex()}`);
  console.log(`  Parent: ${header.parentHash.toHex()}`);
  console.log(`  State root: ${header.stateRoot.toHex()}`);
  console.log(`  Extrinsics root: ${header.extrinsicsRoot.toHex()}`);
});

// Unsubscribe after 60 seconds
setTimeout(() => {
  unsubscribe();
  api.disconnect();
}, 60000);
```

```python
import asyncio
import websockets
import json

async def subscribe_new_heads():
    uri = 'wss://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    async with websockets.connect(uri) as ws:
        # Subscribe to new heads
        await ws.send(json.dumps({
            'jsonrpc': '2.0',
            'method': 'chain_subscribeNewHeads',
            'params': [],
            'id': 1
        }))

        # Get subscription ID
        response = json.loads(await ws.recv())
        sub_id = response['result']
        print(f'Subscribed with ID: {sub_id}')

        # Listen for new headers
        while True:
            message = json.loads(await ws.recv())
            if 'params' in message:
                header = message['params']['result']
                block_num = int(header['number'], 16)
                print(f"Block #{block_num}")
                print(f"  Parent: {header['parentHash']}")
                print(f"  State root: {header['stateRoot']}")

asyncio.run(subscribe_new_heads())
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    let mut new_heads = api.rpc()
        .subscribe_all_block_headers()
        .await?;

    while let Some(Ok(header)) = new_heads.next().await {
        println!(
            "New block #{}: {:?}",
            header.number,
            header.hash()
        );
    }

    Ok(())
}
```

## Common Use Cases

### 1. Real-Time Block Indexer

Index new blocks and their events on XX Network as they arrive:

```javascript
async function indexBlocks(api, onBlock) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const blockHash = header.hash;
    const [block, events] = await Promise.all([
      api.rpc.chain.getBlock(blockHash),
      api.query.system.events.at(blockHash)
    ]);

    const blockData = {
      number: header.number.toNumber(),
      hash: blockHash.toHex(),
      parentHash: header.parentHash.toHex(),
      extrinsicCount: block.block.extrinsics.length,
      eventCount: events.length,
      timestamp: Date.now()
    };

    await onBlock(blockData);
  });

  return unsub;
}
```

### 2. Block Production Monitor

Detect block production delays on XX Network:

```javascript
async function monitorBlockProduction(api, expectedBlockTimeMs = 6000) {
  let lastBlockTime = Date.now();
  const threshold = expectedBlockTimeMs * 3;

  const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
    const now = Date.now();
    const elapsed = now - lastBlockTime;

    if (elapsed > threshold) {
      console.warn(
        `Block #${header.number}: ${elapsed}ms since last block (expected ~${expectedBlockTimeMs}ms)`
      );
    } else {
      console.log(`Block #${header.number}: ${elapsed}ms`);
    }

    lastBlockTime = now;
  });

  return unsub;
}
```

### 3. Live Dashboard Feed

Stream block data to a WebSocket-connected frontend:

```javascript
async function streamToClients(api, wss) {
  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const message = JSON.stringify({
      type: 'new_block',
      number: header.number.toNumber(),
      hash: header.hash.toHex(),
      parentHash: header.parentHash.toHex(),
      stateRoot: header.stateRoot.toHex()
    });

    wss.clients.forEach((client) => {
      if (client.readyState === 1) {
        client.send(message);
      }
    });
  });

  return unsub;
}
```

## Subscription vs Polling

| Approach            | Latency                    | Resource Usage             | Use Case                       |
| ------------------- | -------------------------- | -------------------------- | ------------------------------ |
| `subscribeNewHeads` | Immediate                  | Low (push-based)           | Real-time monitoring, indexing |
| Polling `getHeader` | Block time + poll interval | Higher (repeated requests) | Simple integrations, HTTP-only |

## Related Methods

- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeFinalizedHeads) - Subscribe to finalized blocks only (for irreversible state)
- [`chain_getHeader`](https://www.dwellir.com/docs/xx-network/chain_getHeader) - Get a specific block header by hash
- [`chain_getBlock`](https://www.dwellir.com/docs/xx-network/chain_getBlock) - Get full block data with extrinsics
- `chain_unsubscribeNewHeads` - Unsubscribe from new heads

---

## grandpa_roundState - XX Network RPC Method

# grandpa_roundState - XX Network RPC Method

Returns the state of the current GRANDPA finality round on XX Network when the endpoint exposes validator-round internals. GRANDPA (GHOST-based Recursive ANcestor Deriving Prefix Agreement) is the finality gadget used by many Substrate-based chains to provide deterministic finality, but some public endpoints do not surface `grandpa_roundState` and instead return a method-not-found style error.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`grandpa_roundState` is essential for XX Network developers building privacy-preserving applications:

- **Finality Monitoring** -- Track whether GRANDPA rounds are progressing normally or stalling on XX Network, critical for secure messaging, private payments, and quantum-resistant cryptography
- **Consensus Health Checks** -- Detect finality delays by comparing prevote/precommit counts against the supermajority threshold weight
- **Validator Participation Analysis** -- Monitor which validators are actively voting and whether the authority set has sufficient online weight
- **Authority Set Tracking** -- Observe `setId` changes after validator set rotations to verify smooth authority transitions
- **Capability Detection** -- Confirm whether the shared endpoint exposes GRANDPA round internals before you build monitoring around them

## Best Practices

- Primarily used for network monitoring and consensus debugging
- Returns `prevotes` and `precommits` from active validators
- Response may be large on networks with many validators
- Most applications should use `chain_getFinalizedHead` instead for finality tracking

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "grandpa_roundState",
  "params": [],
  "id": 1
}
```

## Response Fields

- `setId` (`u64, required`): The current GRANDPA authority set ID; increments when the validator set changes
- `best` (`RoundState, required`): State of the best (most recent) active round
- `background` (`Vec<RoundState>, required`): Background rounds that are still being tracked (typically the previous round)
- `round` (`u64, required`): The round number
- `totalWeight` (`u64, required`): Total combined weight of all authorities in this set
- `thresholdWeight` (`u64, required`): Minimum weight required for a supermajority (2/3 + 1 of totalWeight)
- `prevotes` (`Votes, required`): Current prevote state for this round
- `precommits` (`Votes, required`): Current precommit state for this round
- `currentWeight` (`u64, required`): Total weight of votes received so far
- `missing` (`Vec<AuthorityId>, required`): List of authority public keys that have not yet voted

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "setId": 4821,
    "best": {
      "round": 19384,
      "totalWeight": 297,
      "thresholdWeight": 199,
      "prevotes": {
        "currentWeight": 297,
        "missing": []
      },
      "precommits": {
        "currentWeight": 264,
        "missing": [
          "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
          "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
        ]
      }
    },
    "background": []
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "grandpa_roundState",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

try {
  const roundState = await api.rpc.grandpa.roundState();
  const best = roundState.best;

  console.log('Authority set ID:', roundState.setId.toString());
  console.log('Round:', best.round.toString());
  console.log('Total weight:', best.totalWeight.toString());
  console.log('Threshold weight:', best.thresholdWeight.toString());
  console.log('Prevote weight:', best.prevotes.currentWeight.toString());
  console.log('Precommit weight:', best.precommits.currentWeight.toString());
  console.log('Missing precommits:', best.precommits.missing.length);
} catch (error) {
  console.log('grandpa_roundState unsupported:', error.message);
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'grandpa_roundState',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('grandpa_roundState unsupported:', payload.error.message);
} else {
  console.log('Set ID:', payload.result.setId);
  console.log('Best round:', payload.result.best.round);
  console.log('Prevote progress:', payload.result.best.prevotes.currentWeight, '/', payload.result.best.thresholdWeight);
  console.log('Precommit progress:', payload.result.best.precommits.currentWeight, '/', payload.result.best.thresholdWeight);
}
```

```python
import requests

def get_grandpa_round_state():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'grandpa_roundState',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

try:
    state = get_grandpa_round_state()
    best = state['best']

    print(f"Authority set ID: {state['setId']}")
    print(f"Round: {best['round']}")
    print(f"Prevote: {best['prevotes']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Precommit: {best['precommits']['currentWeight']}/{best['thresholdWeight']}")
    print(f"Missing precommit voters: {len(best['precommits']['missing'])}")
except KeyError:
    print('grandpa_roundState unsupported on this endpoint')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
response = substrate.rpc_request('grandpa_roundState', [])
if 'error' in response:
    print(f"grandpa_roundState unsupported: {response['error']['message']}")
else:
    print(f"Set ID: {response['result']['setId']}, Round: {response['result']['best']['round']}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
    set_id: u64,
    best: BestRound,
    background: Vec<BestRound>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BestRound {
    round: u64,
    total_weight: u64,
    threshold_weight: u64,
    prevotes: Votes,
    precommits: Votes,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Votes {
    current_weight: u64,
    missing: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "grandpa_roundState",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    if body.get("error").is_some() {
        println!("grandpa_roundState unsupported: {}", body["error"]["message"]);
        return Ok(());
    }

    let state: RoundState = serde_json::from_value(body["result"].clone())?;

    println!("Set ID: {}", state.set_id);
    println!("Round: {}", state.best.round);
    println!("Prevote: {}/{}", state.best.prevotes.current_weight, state.best.threshold_weight);
    println!("Precommit: {}/{}", state.best.precommits.current_weight, state.best.threshold_weight);
    println!("Missing precommit voters: {}", state.best.precommits.missing.len());

    Ok(())
}
```

## Common Use Cases

### 1. Finality Health Monitoring

Periodically check whether GRANDPA rounds are progressing and alert on stalls:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorFinality(api, intervalMs = 10000) {
  let lastRound = 0;
  let lastSetId = 0;
  let stallCount = 0;

  setInterval(async () => {
    const state = await api.rpc.grandpa.roundState();
    const best = state.best;
    const round = best.round.toNumber();
    const setId = state.setId.toNumber();
    const prevoteProgress = best.prevotes.currentWeight.toNumber();
    const precommitProgress = best.precommits.currentWeight.toNumber();
    const threshold = best.thresholdWeight.toNumber();

    if (setId !== lastSetId) {
      console.log(`Authority set changed: ${lastSetId} -> ${setId}`);
      lastSetId = setId;
    }

    if (round === lastRound) {
      stallCount++;
      if (stallCount >= 3) {
        console.warn(`GRANDPA round ${round} stalled for ${stallCount} checks`);
        console.warn(`  Prevotes: ${prevoteProgress}/${threshold}`);
        console.warn(`  Precommits: ${precommitProgress}/${threshold}`);
        console.warn(`  Missing voters: ${best.precommits.missing.length}`);
      }
    } else {
      stallCount = 0;
      console.log(`Round ${round} | prevotes=${prevoteProgress}/${threshold} precommits=${precommitProgress}/${threshold}`);
    }

    lastRound = round;
  }, intervalMs);
}
```

### 2. Validator Participation Report

Generate a report of which validators are consistently missing votes:

```javascript
async function trackMissingVoters(api, samples = 20, delayMs = 6000) {
  const missingCounts = {};

  for (let i = 0; i < samples; i++) {
    const state = await api.rpc.grandpa.roundState();
    const missing = state.best.precommits.missing;

    missing.forEach((authority) => {
      const key = authority.toString();
      missingCounts[key] = (missingCounts[key] || 0) + 1;
    });

    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  // Sort by most frequently missing
  const sorted = Object.entries(missingCounts)
    .sort(([, a], [, b]) => b - a);

  console.log('Validator participation report:');
  sorted.forEach(([authority, count]) => {
    const missRate = ((count / samples) * 100).toFixed(1);
    console.log(`  ${authority}: missed ${count}/${samples} (${missRate}%)`);
  });

  return sorted;
}
```

### 3. Supported-Fallback Check

If the endpoint does not expose GRANDPA round internals, fall back to finalized-head tracking:

```javascript
async function getFinalitySignal(api) {
  try {
    return { supported: true, roundState: await api.rpc.grandpa.roundState() };
  } catch (error) {
    return {
      supported: false,
      finalizedHead: (await api.rpc.chain.getFinalizedHead()).toHex(),
      message: error.message
    };
  }
}
```

### 3. Finality Lag Detection

Compare the finalized head with the best block to measure finality lag:

```javascript
async function getFinalityLag(api) {
  const [roundState, finalizedHash, bestHeader] = await Promise.all([
    api.rpc.grandpa.roundState(),
    api.rpc.chain.getFinalizedHead(),
    api.rpc.chain.getHeader()
  ]);

  const finalizedHeader = await api.rpc.chain.getHeader(finalizedHash);
  const bestNumber = bestHeader.number.toNumber();
  const finalizedNumber = finalizedHeader.number.toNumber();
  const lag = bestNumber - finalizedNumber;

  return {
    bestBlock: bestNumber,
    finalizedBlock: finalizedNumber,
    lagBlocks: lag,
    grandpaRound: roundState.best.round.toNumber(),
    setId: roundState.setId.toNumber(),
    prevoteReached: roundState.best.prevotes.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber(),
    precommitReached: roundState.best.precommits.currentWeight.toNumber() >= roundState.best.thresholdWeight.toNumber()
  };
}
```

## Understanding GRANDPA Rounds

GRANDPA achieves finality through a two-phase voting protocol:

1. **Prevote Phase** -- Each authority broadcasts a prevote for the highest block they consider best. Once prevotes reach the `thresholdWeight` (supermajority), the protocol derives the highest block that is an ancestor of all supermajority prevotes.

2. **Precommit Phase** -- Authorities that observe a supermajority of prevotes issue precommits for the block derived in the prevote phase. When precommits reach the threshold, that block and all its ancestors are finalized.

3. **Authority Sets** -- The `setId` increments each time the authority set changes (e.g., after a session rotation). A new authority set starts a new round sequence from round 1.

| Concept             | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **totalWeight**     | Sum of all authority weights in the current set                                               |
| **thresholdWeight** | `⌊totalWeight × 2/3⌋ + 1` -- minimum for supermajority                                        |
| **Healthy round**   | `prevotes.currentWeight >= thresholdWeight` AND `precommits.currentWeight >= thresholdWeight` |
| **Stalled round**   | Neither prevotes nor precommits reach threshold for an extended period                        |

## Related Methods

- [`chain_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/chain_getFinalizedHead) -- Get the hash of the latest finalized block
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeFinalizedHeads) -- Subscribe to new finalized block headers
- `grandpa_proveFinality` -- Get a finality proof for a specific block number
- [`beefy_getFinalizedHead`](https://www.dwellir.com/docs/xx-network/beefy_getFinalizedHead) -- Get the latest BEEFY finalized block (if BEEFY is enabled)
- [`system_health`](https://www.dwellir.com/docs/xx-network/system_health) -- Check overall node health including sync and peer status

---

## payment_queryFeeDetails - XX Network RPC Method

# payment_queryFeeDetails - XX Network RPC Method

Returns a detailed breakdown of the inclusion fee for a given extrinsic on XX Network. While `payment_queryInfo` returns the total fee as a single value, this method separates it into three components: the fixed base fee, the length-proportional fee, and the weight-based adjusted fee. This granularity is essential for understanding and optimizing transaction costs.

If you provide `blockHash`, it must be a real chain block hash. Placeholder hashes and stale examples return an `unknown Block` style error.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`payment_queryFeeDetails` is essential for XX Network developers building privacy-preserving applications:

- **Fee Optimization** -- Identify which fee component dominates your transaction cost and optimize accordingly on XX Network
- **Transaction Cost Analysis** -- Build detailed cost breakdowns for secure messaging, private payments, and quantum-resistant cryptography, showing users exactly where their fees go
- **Fee Model Comparison** -- Compare fee structures across different extrinsic types or between runtime upgrades that change fee parameters
- **Batching Decisions** -- Determine whether batching calls saves fees by amortizing the base fee across multiple operations

## Best Practices

- Returns `baseFee`, `lenFee`, and `adjustedWeightFee` for detailed cost analysis
- More granular than `payment_queryInfo` -- useful for gas optimization
- Fee components are calculated from weight and length of the extrinsic
- Weight-adjusted fees may vary based on current network congestion

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded SCALE-serialized extrinsic (signed or unsigned)
- `blockHash` (`String, optional`): Block hash at which to calculate fees; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryFeeDetails",
  "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
  "id": 1
}
```

## Response Fields

- `inclusionFee` (`Option<InclusionFee>, required`): Fee breakdown object, or null if the extrinsic does not pay fees
- `baseFee` (`String, required`): Fixed fee charged per extrinsic regardless of size or complexity (human-readable decimal string)
- `lenFee` (`String, required`): Fee proportional to the encoded byte length of the extrinsic (length * lengthToFee)
- `adjustedWeightFee` (`String, required`): Fee based on execution weight, adjusted by the current block fullness multiplier

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "inclusionFee": {
      "baseFee": "124414000000",
      "lenFee": "1430000000",
      "adjustedWeightFee": "2183055836"
    }
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: Could not decode extrinsic"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query fee details for an encoded extrinsic
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": ["0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01..."],
    "id": 1
  }'

# Query fee details at a specific block
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryFeeDetails",
    "params": [
      "0x2d028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01...",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a sample transfer extrinsic
const tx = api.tx.balances.transferKeepAlive(
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
  1000000000000n
);

// Get fee details
const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

if (feeDetails.inclusionFee.isSome) {
  const fee = feeDetails.inclusionFee.unwrap();
  console.log('Base fee:', fee.baseFee.toString());
  console.log('Length fee:', fee.lenFee.toString());
  console.log('Weight fee:', fee.adjustedWeightFee.toString());

  const total = fee.baseFee.add(fee.lenFee).add(fee.adjustedWeightFee);
  console.log('Total inclusion fee:', total.toString());
}

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryFeeDetails',
    params: ['0x2d028400...signedExtrinsicHex'],
    id: 1
  })
});

const { result } = await response.json();
if (result.inclusionFee) {
  console.log('Fee components:', result.inclusionFee);
}
```

```python
import requests

def query_fee_details(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryFeeDetails',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee details for an encoded extrinsic
encoded_extrinsic = '0x2d028400...'
result = query_fee_details(encoded_extrinsic)

if result['inclusionFee']:
    fee = result['inclusionFee']
    base = int(fee['baseFee'])
    length = int(fee['lenFee'])
    weight = int(fee['adjustedWeightFee'])
    total = base + length + weight

    print(f"Base fee:   {base:>20} planck")
    print(f"Length fee: {length:>20} planck")
    print(f"Weight fee: {weight:>20} planck")
    print(f"Total:      {total:>20} planck")
else:
    print('Extrinsic does not pay fees')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('payment_queryFeeDetails', [encoded_extrinsic])['result']
print(f"Fee details: {result}")
```

```rust
use serde_json::json;

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct FeeDetailsResponse {
    inclusion_fee: Option<InclusionFee>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct InclusionFee {
    base_fee: String,
    len_fee: String,
    adjusted_weight_fee: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x2d028400...";

    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryFeeDetails",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let body: serde_json::Value = response.json().await?;
    let details: FeeDetailsResponse = serde_json::from_value(body["result"].clone())?;

    match details.inclusion_fee {
        Some(fee) => {
            let base: u128 = fee.base_fee.parse()?;
            let len: u128 = fee.len_fee.parse()?;
            let weight: u128 = fee.adjusted_weight_fee.parse()?;
            let total = base + len + weight;

            println!("Base fee:   {:>20}", base);
            println!("Length fee: {:>20}", len);
            println!("Weight fee: {:>20}", weight);
            println!("Total:      {:>20}", total);
        }
        None => println!("Extrinsic does not pay fees"),
    }

    Ok(())
}
```

## Common Use Cases

### 1. Fee Component Analysis for Optimization

Analyze which fee component dominates to guide optimization strategies:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function analyzeFeeComponents(api, tx) {
  const feeDetails = await api.rpc.payment.queryFeeDetails(tx.toHex());

  if (feeDetails.inclusionFee.isNone) {
    return { feeless: true };
  }

  const fee = feeDetails.inclusionFee.unwrap();
  const base = BigInt(fee.baseFee.toString());
  const len = BigInt(fee.lenFee.toString());
  const weight = BigInt(fee.adjustedWeightFee.toString());
  const total = base + len + weight;

  const analysis = {
    baseFee: { value: base, percentage: Number((base * 10000n) / total) / 100 },
    lenFee: { value: len, percentage: Number((len * 10000n) / total) / 100 },
    weightFee: { value: weight, percentage: Number((weight * 10000n) / total) / 100 },
    total
  };

  // Suggest optimization based on dominant component
  if (analysis.lenFee.percentage > 50) {
    analysis.suggestion = 'Length fee dominates -- reduce call data size or batch smaller calls';
  } else if (analysis.weightFee.percentage > 50) {
    analysis.suggestion = 'Weight fee dominates -- choose lighter runtime operations';
  } else {
    analysis.suggestion = 'Fees are balanced -- batch calls to amortize base fee';
  }

  return analysis;
}
```

### 2. Batch vs. Individual Fee Comparison

Compare the cost of batching calls versus submitting them individually:

```javascript
async function compareBatchVsIndividual(api, calls) {
  // Individual fee total
  let individualTotal = 0n;
  for (const call of calls) {
    const tx = api.tx(call);
    const details = await api.rpc.payment.queryFeeDetails(tx.toHex());
    if (details.inclusionFee.isSome) {
      const fee = details.inclusionFee.unwrap();
      individualTotal += BigInt(fee.baseFee.toString())
        + BigInt(fee.lenFee.toString())
        + BigInt(fee.adjustedWeightFee.toString());
    }
  }

  // Batched fee
  const batchTx = api.tx.utility.batchAll(calls);
  const batchDetails = await api.rpc.payment.queryFeeDetails(batchTx.toHex());
  let batchTotal = 0n;
  if (batchDetails.inclusionFee.isSome) {
    const fee = batchDetails.inclusionFee.unwrap();
    batchTotal = BigInt(fee.baseFee.toString())
      + BigInt(fee.lenFee.toString())
      + BigInt(fee.adjustedWeightFee.toString());
  }

  const savings = individualTotal - batchTotal;
  console.log(`Individual total: ${individualTotal} planck`);
  console.log(`Batch total:      ${batchTotal} planck`);
  console.log(`Savings:          ${savings} planck (${Number((savings * 10000n) / individualTotal) / 100}%)`);

  return { individualTotal, batchTotal, savings };
}
```

### 3. Fee Tracking Across Runtime Upgrades

Monitor how fee components change after runtime upgrades to detect regressions:

```javascript
async function compareFeesBetweenBlocks(api, extrinsicHex, blockHashBefore, blockHashAfter) {
  const [before, after] = await Promise.all([
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashBefore),
    api.rpc.payment.queryFeeDetails(extrinsicHex, blockHashAfter)
  ]);

  function extractFees(details) {
    if (details.inclusionFee.isNone) return null;
    const fee = details.inclusionFee.unwrap();
    return {
      base: BigInt(fee.baseFee.toString()),
      len: BigInt(fee.lenFee.toString()),
      weight: BigInt(fee.adjustedWeightFee.toString())
    };
  }

  const feesBefore = extractFees(before);
  const feesAfter = extractFees(after);

  if (feesBefore && feesAfter) {
    console.log('Fee comparison:');
    console.log(`  Base fee:   ${feesBefore.base} -> ${feesAfter.base}`);
    console.log(`  Length fee: ${feesBefore.len} -> ${feesAfter.len}`);
    console.log(`  Weight fee: ${feesBefore.weight} -> ${feesAfter.weight}`);
  }
}
```

## Fee Components Explained

| Component             | Source                | How It's Calculated                                                                      | Optimization Strategy                                                                     |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **baseFee**           | `ExtrinsicBaseWeight` | Fixed cost per extrinsic defined by the runtime                                          | Batch multiple calls into a single extrinsic to pay only one base fee                     |
| **lenFee**            | `TransactionByteFee`  | `encodedLength × lengthToFee` coefficient                                                | Minimize encoded extrinsic size by using compact encodings and avoiding large payloads    |
| **adjustedWeightFee** | `WeightToFee`         | Execution weight multiplied by the fee multiplier, which adjusts based on block fullness | Choose lighter operations, submit during low-traffic periods when the multiplier is lower |

**Tip multiplier**: The `adjustedWeightFee` is sensitive to network congestion. When blocks are consistently more than half full, the fee multiplier increases, raising the weight fee. During low-traffic periods, the multiplier decreases toward its minimum.

## Related Methods

- [`payment_queryInfo`](https://www.dwellir.com/docs/xx-network/payment_queryInfo) -- Get the total fee and execution weight for an extrinsic as a single value
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) -- Call `TransactionPaymentApi_query_fee_details` directly for more control
- [`system_properties`](https://www.dwellir.com/docs/xx-network/system_properties) -- Get token decimals and symbol for human-readable fee display
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/xx-network/author_submitExtrinsic) -- Submit the extrinsic after confirming acceptable fees
- [`author_submitAndWatchExtrinsic`](https://www.dwellir.com/docs/xx-network/author_submitAndWatchExtrinsic) -- Submit and track the extrinsic through finalization

---

## payment_queryInfo - XX Network RPC Method

# payment_queryInfo - XX Network RPC Method

Estimates the fee for an encoded extrinsic on XX Network. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`payment_queryInfo` is essential for XX Network developers building privacy-preserving applications:

- **Fee Display** -- Show users the estimated transaction cost before they sign on XX Network
- **Balance Validation** -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for secure messaging, private payments, and quantum-resistant cryptography
- **Transaction Planning** -- Compare fees across different extrinsic types to optimize costs
- **Batch Cost Estimation** -- Estimate the total cost of batch transactions before submission

## Best Practices

- Fees may change before extrinsic inclusion due to network conditions
- The `partialFee` is returned in planck (smallest unit of the native token)
- Test with actual encoded extrinsic data for the most accurate fee estimate
- Use `payment_queryFeeDetails` for a component-level fee breakdown

## Request Parameters

- `extrinsic` (`String, required`): Hex-encoded signed or unsigned extrinsic
- `blockHash` (`String, optional`): Block hash for fee calculation context; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "payment_queryInfo",
  "params": ["0x4d0284ff..."],
  "id": 1
}
```

## Response Fields

- `weight` (`Object, required`): The dispatch weight of the extrinsic, containing refTime (compute) and proofSize (storage proof)
- `class` (`String, required`): The dispatch class: "Normal", "Operational", or "Mandatory"
- `partialFee` (`String, required`): The estimated fee in the chain's smallest unit (e.g., Planck for Polkadot). Does not include tip

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "weight": {
      "refTime": 216215000,
      "proofSize": 3593
    },
    "class": "Normal",
    "partialFee": "157000152"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Unable to query dispatch info"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "payment_queryInfo",
    "params": ["0x4d0284ff..."],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Create a transfer extrinsic
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000; // Example base-unit amount; adjust for the chain's native decimals
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);

// Query fee info using a sender address
const sender = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const info = await transfer.paymentInfo(sender);

console.log('Partial fee:', info.partialFee.toHuman());
console.log('Weight:', info.weight.toString());
console.log('Class:', info.class.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a pre-encoded extrinsic
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'payment_queryInfo',
    params: [transfer.toHex()],
    id: 1
  })
});

const { result } = await response.json();
console.log('Fee estimate:', result.partialFee);
```

```python
import requests

def query_fee_info(extrinsic_hex, block_hash=None):
    params = [extrinsic_hex]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'payment_queryInfo',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query fee for a pre-built extrinsic
extrinsic_hex = '0x4d0284ff...'
info = query_fee_info(extrinsic_hex)
print(f"Partial fee: {info['partialFee']}")
print(f"Weight: {info['weight']}")
print(f"Class: {info['class']}")

# Using substrate-interface
from substrateinterface import SubstrateInterface, Keypair

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')

# Build a transfer call
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer_keep_alive',
    call_params={
        'dest': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
        'value': 1000000000000
    }
)

# Create extrinsic for fee estimation
keypair = Keypair.create_from_uri('//Alice')
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
info = substrate.get_payment_info(call=call, keypair=keypair)
print(f"Estimated fee: {info['partialFee']}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DispatchInfo {
    weight: Weight,
    class: String,
    partial_fee: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Weight {
    ref_time: u64,
    proof_size: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let extrinsic_hex = "0x4d0284ff..."; // pre-encoded extrinsic

    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "payment_queryInfo",
            "params": [extrinsic_hex],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let info: DispatchInfo = serde_json::from_value(result["result"].clone())?;

    println!("Partial fee: {}", info.partial_fee);
    println!("Weight: refTime={}, proofSize={}", info.weight.ref_time, info.weight.proof_size);
    println!("Class: {}", info.class);
    Ok(())
}
```

## Common Use Cases

### 1. Pre-Transaction Fee Display

Show fees to users before they confirm a transaction:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function displayFeeEstimate(api, extrinsic, senderAddress) {
  const [info, properties] = await Promise.all([
    extrinsic.paymentInfo(senderAddress),
    api.rpc.system.properties()
  ]);

  const decimals = properties.tokenDecimals.toJSON()[0];
  const symbol = properties.tokenSymbol.toJSON()[0];
  const fee = info.partialFee;

  // Convert to human-readable
  const divisor = new BN(10).pow(new BN(decimals));
  const whole = fee.div(divisor);
  const fractional = fee.mod(divisor).toString().padStart(decimals, '0');

  const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
  console.log(`Estimated fee: ${formatted}`);
  console.log(`Dispatch class: ${info.class.toString()}`);

  return { fee: fee.toString(), formatted, class: info.class.toString() };
}
```

### 2. Sufficient Balance Check

Verify the sender can afford the transaction plus fees:

```javascript
async function canAffordTransaction(api, senderAddress, recipient, amount) {
  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const [info, account] = await Promise.all([
    transfer.paymentInfo(senderAddress),
    api.query.system.account(senderAddress)
  ]);

  const fee = info.partialFee.toBigInt();
  const transferAmount = BigInt(amount);
  const totalCost = fee + transferAmount;
  const freeBalance = account.data.free.toBigInt();

  // Account for existential deposit
  const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
  const available = freeBalance - existentialDeposit;

  const canAfford = available >= totalCost;

  console.log(`Free balance: ${freeBalance}`);
  console.log(`Total cost (amount + fee): ${totalCost}`);
  console.log(`Can afford: ${canAfford}`);

  return canAfford;
}
```

### 3. Compare Fees Across Transaction Types

Estimate fees for different operations to find the cheapest approach:

```javascript
async function compareFees(api, sender) {
  const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
  const amount = 1000000000000;

  // Different transaction types
  const extrinsics = {
    'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
    'transferAll': api.tx.balances.transferAll(recipient, false),
    'batchTransfer': api.tx.utility.batchAll([
      api.tx.balances.transferKeepAlive(recipient, amount / 2),
      api.tx.balances.transferKeepAlive(recipient, amount / 2)
    ])
  };

  const fees = {};
  for (const [name, ext] of Object.entries(extrinsics)) {
    const info = await ext.paymentInfo(sender);
    fees[name] = {
      partialFee: info.partialFee.toHuman(),
      weight: info.weight.toString(),
      class: info.class.toString()
    };
  }

  console.table(fees);
  return fees;
}
```

## Related Methods

- [`author_submitExtrinsic`](https://www.dwellir.com/docs/xx-network/author_submitExtrinsic) -- Submit the extrinsic after verifying the fee
- [`payment_queryFeeDetails`](https://www.dwellir.com/docs/xx-network/payment_queryFeeDetails) -- Get a detailed fee breakdown (base fee, length fee, weight fee)
- [`system_properties`](https://www.dwellir.com/docs/xx-network/system_properties) -- Get token decimals and symbol for formatting the fee
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) -- Call `TransactionPaymentApi` directly for advanced fee queries
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/xx-network/author_pendingExtrinsics) -- Check pending extrinsics in the pool

---

## rpc_methods - XX Network RPC Method

# rpc_methods - XX Network RPC Method

Returns a list of all RPC methods exposed by the XX Network node. This is the definitive way to discover what methods are available on a given endpoint, including both standard Substrate methods and any custom chain-specific extensions.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`rpc_methods` is essential for XX Network developers building privacy-preserving applications:

- **API Discovery** -- Enumerate all available RPC methods to understand the full capabilities of a XX Network node
- **Capability Detection** -- Check whether a specific method (e.g., `author_submitExtrinsic`, `state_call`) is available before calling it
- **Compatibility Testing** -- Verify that an endpoint supports the methods your application requires for secure messaging, private payments, and quantum-resistant cryptography
- **Tooling and Documentation** -- Auto-generate API references or client SDKs from the available method list

## Best Practices

- Call at application startup to discover available RPC capabilities
- Use to gate feature availability -- only call methods that appear in the returned list
- Method availability varies by node configuration and Substrate runtime version
- Verified: a standard Polkadot archive node exposes approximately 129 methods across all namespaces

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_methods",
  "params": [],
  "id": 1
}
```

## Response Fields

- `methods` (`Array<String>, required`): A sorted list of all available RPC method names

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "methods": [
      "author_pendingExtrinsics",
      "author_submitExtrinsic",
      "chain_getBlock",
      "chain_getBlockHash",
      "chain_getHeader",
      "payment_queryInfo",
      "rpc_methods",
      "state_call",
      "state_getKeysPaged",
      "state_getMetadata",
      "state_getStorage",
      "state_queryStorageAt",
      "system_chain",
      "system_name",
      "system_properties",
      "system_version"
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_methods",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const methods = await api.rpc.rpc.methods();
console.log('Available methods:', methods.methods.length);
methods.methods.forEach((m) => console.log(' -', m.toString()));

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rpc_methods',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.methods.length} available methods`);
```

```python
import requests

def get_rpc_methods():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'rpc_methods',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']['methods']

methods = get_rpc_methods()
print(f'Available RPC methods ({len(methods)}):')
for method in methods:
    print(f'  - {method}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('rpc_methods', [])['result']
print(f"Methods: {len(result['methods'])}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct RpcMethodsResult {
    methods: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "rpc_methods",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let rpc: RpcMethodsResult = serde_json::from_value(result["result"].clone())?;

    println!("Available methods ({}):", rpc.methods.len());
    for method in &rpc.methods {
        println!("  - {}", method);
    }
    Ok(())
}
```

## Common Use Cases

### 1. Endpoint Capability Validation

Check whether a XX Network endpoint supports all methods your application needs:

```javascript
async function validateEndpoint(endpoint, requiredMethods) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'rpc_methods',
      params: [],
      id: 1
    })
  });

  const { result } = await response.json();
  const available = new Set(result.methods);

  const missing = requiredMethods.filter((m) => !available.has(m));

  if (missing.length > 0) {
    console.error('Missing required methods:', missing);
    return false;
  }

  console.log('Endpoint supports all required methods');
  return true;
}

// Usage
await validateEndpoint('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', [
  'state_getStorage',
  'state_call',
  'author_submitExtrinsic',
  'payment_queryInfo'
]);
```

### 2. Method Category Breakdown

Organize available methods by their RPC namespace:

```javascript
async function getMethodsByCategory(api) {
  const methods = await api.rpc.rpc.methods();
  const categories = {};

  methods.methods.forEach((method) => {
    const name = method.toString();
    const category = name.split('_')[0];
    categories[category] = categories[category] || [];
    categories[category].push(name);
  });

  for (const [category, methodList] of Object.entries(categories)) {
    console.log(`\n${category} (${methodList.length} methods):`);
    methodList.forEach((m) => console.log(`  - ${m}`));
  }

  return categories;
}
```

### 3. Compare Endpoints

Detect differences between two XX Network endpoints:

```javascript
async function compareEndpoints(endpoint1, endpoint2) {
  const fetchMethods = async (url) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ jsonrpc: '2.0', method: 'rpc_methods', params: [], id: 1 })
    });
    const { result } = await res.json();
    return new Set(result.methods);
  };

  const [methods1, methods2] = await Promise.all([
    fetchMethods(endpoint1),
    fetchMethods(endpoint2)
  ]);

  const onlyIn1 = [...methods1].filter((m) => !methods2.has(m));
  const onlyIn2 = [...methods2].filter((m) => !methods1.has(m));

  if (onlyIn1.length) console.log('Only in endpoint 1:', onlyIn1);
  if (onlyIn2.length) console.log('Only in endpoint 2:', onlyIn2);
  if (!onlyIn1.length && !onlyIn2.length) console.log('Endpoints have identical methods');
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/xx-network/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/xx-network/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) -- Get full runtime metadata including pallet and call definitions

---

## state_call - XX Network RPC Method

# state_call - XX Network RPC Method

Calls a runtime API function on XX Network and returns the SCALE-encoded result. This method lets you execute runtime logic (such as `AccountNonceApi`, `TransactionPaymentApi`, or any custom runtime API) without submitting a transaction.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`state_call` is essential for XX Network developers building privacy-preserving applications:

- **Account Nonce Queries** -- Retrieve the next nonce for an account via `AccountNonceApi_account_nonce` before constructing extrinsics
- **Fee Estimation** -- Use `TransactionPaymentApi_query_info` to estimate fees for secure messaging, private payments, and quantum-resistant cryptography
- **Custom Runtime APIs** -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
- **Historical State Queries** -- Execute runtime logic at a specific block by providing an optional block hash

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## Common Use Cases

### 1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}
```

### 2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

```javascript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);
```

### 3. Historical State Query

Execute a runtime API call against a historical block:

```javascript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/xx-network/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/xx-network/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/xx-network/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) -- Get the node version for compatibility checking

---

## state_getKeys - JSON-RPC Method

# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-xxnetwork.n.dwellir.com/YOUR_API_KEY"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-xxnetwork.n.dwellir.com/YOUR_API_KEY', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

```typescript
import { ApiPromise, WsProvider } from '@xx-network/api';

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-xxnetwork.n.dwellir.com/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-xxnetwork.n.dwellir.com/YOUR_API_KEY') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/xx-network/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/xx-network/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) - Get metadata to decode keys

---

## state_getKeysPaged - XX Network RPC Method

# state_getKeysPaged - XX Network RPC Method

Returns storage keys matching a prefix with cursor-based pagination on XX Network. This is the standard way to iterate over storage maps (like `System.Account`, `Staking.Validators`, or any pallet storage map) without loading all keys into memory at once.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`state_getKeysPaged` is essential for XX Network developers building privacy-preserving applications:

- **Storage Map Iteration** -- Enumerate all entries in a storage map (accounts, balances, staking data) on XX Network
- **Data Export and Indexing** -- Bulk export on-chain state for analytics, indexers, and data pipelines for secure messaging, private payments, and quantum-resistant cryptography
- **Account Enumeration** -- List all accounts that have balances, staking positions, or other on-chain state
- **State Migration Tooling** -- Iterate storage for runtime upgrades, audits, or cross-chain migration

## Best Practices

- Always use a storage key prefix to limit the result set size
- Paginate through large key sets using the `afterKey` parameter
- Combine with `state_getStorage` to retrieve values for discovered keys
- Use `state_getMetadata` to determine the correct key prefix for each pallet

## Request Parameters

- `prefix` (`String, required`): Hex-encoded storage key prefix to filter by (e.g., the pallet+storage item hash)
- `count` (`Number, required`): Maximum number of keys to return per page (recommended: 100-1000)
- `startKey` (`String, optional`): The last key from the previous page to continue from; omit for the first page
- `blockHash` (`String, optional`): Block hash for historical query; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeysPaged",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
    10
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<String>, required`): Array of hex-encoded storage keys matching the prefix. Returns fewer than count entries (or empty) when the last page is reached

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da900a32c1508ad8e892b07be65125d4ba46",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901c8237c1508a37c72e20f84b137cfb8ed",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Get the first 10 System.Account storage keys
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10
    ],
    "id": 1
  }'

# Continue from the last key (pagination)
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getKeysPaged",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
      10,
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da905c4d73a68eff3a32b6af8adc29e8fc0be"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get first page of System.Account keys
const prefix = api.query.system.account.keyPrefix();
const pageSize = 100;

const firstPage = await api.rpc.state.getKeysPaged(prefix, pageSize);
console.log(`First page: ${firstPage.length} keys`);

// Iterate all pages
async function getAllKeys(api, prefix, pageSize = 100) {
  const allKeys = [];
  let startKey = undefined;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;

    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
    console.log(`Fetched ${allKeys.length} keys so far...`);
  }

  return allKeys;
}

const allAccountKeys = await getAllKeys(api, prefix);
console.log(`Total accounts: ${allAccountKeys.length}`);

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getKeysPaged',
    params: [
      '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9',
      100
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log(`Found ${result.length} keys`);
```

```python
import requests

def get_keys_paged(prefix, count, start_key=None, block_hash=None):
    params = [prefix, count]
    if start_key:
        params.append(start_key)
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getKeysPaged',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

def get_all_keys(prefix, page_size=100):
    """Iterate all storage keys matching a prefix."""
    all_keys = []
    start_key = None

    while True:
        keys = get_keys_paged(prefix, page_size, start_key)
        if not keys:
            break
        all_keys.extend(keys)
        start_key = keys[-1]
        print(f'Fetched {len(all_keys)} keys...')

    return all_keys

# System.Account prefix
prefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9'
all_keys = get_all_keys(prefix)
print(f'Total account keys: {len(all_keys)}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
keys = substrate.rpc_request('state_getKeysPaged', [prefix, 100])['result']
print(f'First page: {len(keys)} keys')
```

```rust
use serde_json::json;

async fn get_keys_paged(
    client: &reqwest::Client,
    url: &str,
    prefix: &str,
    count: u32,
    start_key: Option<&str>,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut params: Vec<serde_json::Value> = vec![
        json!(prefix),
        json!(count),
    ];
    if let Some(key) = start_key {
        params.push(json!(key));
    }

    let response = client
        .post(url)
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getKeysPaged",
            "params": params,
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let keys: Vec<String> = result["result"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap().to_string())
        .collect();

    Ok(keys)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let url = "https://api-xxnetwork.dwellir.com/YOUR_API_KEY";
    let prefix = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9";

    // Paginate through all keys
    let mut all_keys = Vec::new();
    let mut start_key: Option<String> = None;

    loop {
        let keys = get_keys_paged(
            &client, url, prefix, 100,
            start_key.as_deref()
        ).await?;

        if keys.is_empty() { break; }
        start_key = Some(keys.last().unwrap().clone());
        all_keys.extend(keys);
        println!("Fetched {} keys...", all_keys.len());
    }

    println!("Total keys: {}", all_keys.len());
    Ok(())
}
```

## Common Use Cases

### 1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}
```

### 2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

```javascript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');
```

### 3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

```javascript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);
```

ze or add delays between pagination requests |
\| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
\| Timeout | Response too slow | Reduce `count` parameter (try 100 instead of 1000) |

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/xx-network/state_getStorage) -- Get the value for a specific storage key
- [`state_queryStorageAt`](https://www.dwellir.com/docs/xx-network/state_queryStorageAt) -- Batch query multiple storage keys at once
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) -- Get runtime metadata to determine storage key prefixes

---

## state_getMetadata - XX Network RPC Method

# state_getMetadata - XX Network RPC Method

Returns the runtime metadata for XX Network as a SCALE-encoded hex string. Metadata describes all available pallets, storage items, calls, events, errors, and type definitions - everything needed to interact with the chain programmatically.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`state_getMetadata` is essential for XX Network developers building privacy-preserving applications:

- **Runtime Introspection** - Discover available pallets, calls, and storage items on XX Network
- **Extrinsic Building** - Get call signatures and type information for constructing transactions for secure messaging, private payments, and quantum-resistant cryptography
- **Storage Key Generation** - Build correct storage keys from metadata type definitions
- **Client Generation** - Auto-generate typed APIs and SDKs from the runtime metadata
- **Upgrade Awareness** - Detect metadata changes after runtime upgrades

## Best Practices

- Metadata is chain-specific and versioned -- cache for the duration of your session
- Metadata response can be large (500KB+ on complex chains) -- parse it once at startup
- Use metadata to build dynamic UIs that adapt to runtime changes
- The `specVersion` field changes on runtime upgrades -- monitor for incompatibility

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query metadata at. If omitted, returns metadata for the current runtime

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getMetadata",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): SCALE-encoded hex string containing the full runtime metadata

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x6d6574610e...truncated..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getMetadata",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get runtime metadata
const metadata = await api.rpc.state.getMetadata();

// List available pallets
const pallets = metadata.asLatest.pallets.map(p => p.name.toString());
console.log('Available pallets:', pallets);

// Get specific pallet info
const balancesPallet = metadata.asLatest.pallets.find(
  p => p.name.toString() === 'Balances'
);
console.log('Balances pallet index:', balancesPallet.index.toString());

// Check metadata version
console.log('Metadata version:', metadata.version);

await api.disconnect();
```

```python
import requests

def get_metadata(block_hash=None):
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getMetadata',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

metadata_hex = get_metadata()
# Remove '0x' prefix for byte length calculation
byte_length = (len(metadata_hex) - 2) // 2
print(f'Metadata size: {byte_length} bytes ({byte_length / 1024:.1f} KB)')

# For full decoding, use the scalecodec library:
# from scalecodec import ScaleBytes
# from scalecodec.types import MetadataVersioned
# metadata = MetadataVersioned(ScaleBytes(metadata_hex))
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    let metadata = api.rpc()
        .state_get_metadata(None)
        .await?;

    // Access pallet info through the metadata
    let pallets = metadata.pallets();
    for pallet in pallets {
        println!("Pallet: {} (index: {})", pallet.name(), pallet.index());
    }

    Ok(())
}
```

## Common Use Cases

### 1. Discover Available Pallets and Calls

Explore what functionality is available on XX Network:

```javascript
async function explorePallets(api) {
  const metadata = await api.rpc.state.getMetadata();
  const pallets = metadata.asLatest.pallets;

  for (const pallet of pallets) {
    const name = pallet.name.toString();
    const hasCalls = pallet.calls.isSome;
    const hasStorage = pallet.storage.isSome;
    const hasEvents = pallet.events.isSome;

    console.log(`${name}: calls=${hasCalls} storage=${hasStorage} events=${hasEvents}`);
  }
}
```

### 2. Build Storage Keys from Metadata

Generate correct storage keys for querying chain state:

```javascript
import { xxhashAsHex } from '@polkadot/util-crypto';

function buildStorageKey(palletName, storageName) {
  const palletHash = xxhashAsHex(palletName, 128);
  const storageHash = xxhashAsHex(storageName, 128);

  return palletHash + storageHash.slice(2); // Concatenate without duplicate 0x
}

// Example: Build key for System.Account storage
const key = buildStorageKey('System', 'Account');
console.log('Storage prefix key:', key);
```

### 3. Metadata Version Tracking

Track metadata changes across runtime upgrades on XX Network:

```javascript
async function compareMetadataVersions(api, blockA, blockB) {
  const hashA = await api.rpc.chain.getBlockHash(blockA);
  const hashB = await api.rpc.chain.getBlockHash(blockB);

  const metaA = await api.rpc.state.getMetadata(hashA);
  const metaB = await api.rpc.state.getMetadata(hashB);

  const palletsA = new Set(metaA.asLatest.pallets.map(p => p.name.toString()));
  const palletsB = new Set(metaB.asLatest.pallets.map(p => p.name.toString()));

  const added = [...palletsB].filter(p => !palletsA.has(p));
  const removed = [...palletsA].filter(p => !palletsB.has(p));

  console.log('Added pallets:', added);
  console.log('Removed pallets:', removed);
}
```

## Related Methods

- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/xx-network/state_getRuntimeVersion) - Get runtime version (check before re-fetching metadata)
- [`state_getStorage`](https://www.dwellir.com/docs/xx-network/state_getStorage) - Query storage using keys derived from metadata
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) - Call runtime APIs described in metadata

---

## state_getRuntimeVersion - XX Network RPC Method

# state_getRuntimeVersion - XX Network RPC Method

Returns the runtime version information for XX Network, including the spec name, spec version, implementation version, and supported API versions.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`state_getRuntimeVersion` is essential for XX Network developers building privacy-preserving applications:

- **Version Checking** - Verify runtime compatibility before constructing transactions on XX Network
- **Upgrade Detection** - Monitor for runtime upgrades that may change chain behavior for secure messaging, private payments, and quantum-resistant cryptography
- **Transaction Construction** - Include the correct `specVersion` and `transactionVersion` in signed extrinsics
- **API Compatibility** - Check which runtime APIs are available and at what version

## Best Practices

- Track `specVersion` changes to detect runtime upgrades and potential forks
- The `authoringVersion` tracks block authoring protocol compatibility
- Use with `system_health` to verify node is synced before checking version
- Cache version information -- it only changes on runtime upgrades

## Request Parameters

- `blockHash` (`String, optional`): Block hash to query version at. If omitted, returns the current runtime version

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getRuntimeVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `specName` (`String, required`): Runtime specification name (e.g., polkadot, kusama)
- `implName` (`String, required`): Implementation name (e.g., parity-polkadot)
- `authoringVersion` (`Number, required`): Authoring version for block creation
- `specVersion` (`Number, required`): Specification version - incremented on breaking changes
- `implVersion` (`Number, required`): Implementation version - incremented on non-breaking changes
- `transactionVersion` (`Number, required`): Transaction format version - must match when signing
- `stateVersion` (`Number, required`): State trie version
- `apis` (`Array, required`): List of supported runtime API IDs and versions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "specName": "polkadot",
    "implName": "parity-polkadot",
    "authoringVersion": 0,
    "specVersion": 1003000,
    "implVersion": 0,
    "transactionVersion": 26,
    "stateVersion": 1,
    "apis": [
      ["0xdf6acb689907609b", 5],
      ["0x37e397fc7c91f5e4", 2],
      ["0x40fe3ad401f8959a", 6]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getRuntimeVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Get current runtime version
const version = await api.rpc.state.getRuntimeVersion();
console.log('Spec name:', version.specName.toString());
console.log('Spec version:', version.specVersion.toNumber());
console.log('Impl version:', version.implVersion.toNumber());
console.log('Transaction version:', version.transactionVersion.toNumber());

// Get version at a specific block
const blockHash = await api.rpc.chain.getBlockHash(1000000);
const historicalVersion = await api.rpc.state.getRuntimeVersion(blockHash);
console.log('Historical spec version:', historicalVersion.specVersion.toNumber());

await api.disconnect();
```

```python
import requests

def get_runtime_version(block_hash=None):
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'
    params = [block_hash] if block_hash else []

    payload = {
        'jsonrpc': '2.0',
        'method': 'state_getRuntimeVersion',
        'params': params,
        'id': 1
    }

    response = requests.post(url, json=payload)
    return response.json()['result']

version = get_runtime_version()
print(f"Spec: {version['specName']} v{version['specVersion']}")
print(f"Impl: {version['implName']} v{version['implVersion']}")
print(f"Transaction version: {version['transactionVersion']}")
print(f"Supported APIs: {len(version['apis'])}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    let version = api.rpc()
        .state_get_runtime_version(None)
        .await?;

    println!("Spec name: {}", version.spec_name);
    println!("Spec version: {}", version.spec_version);
    println!("Transaction version: {}", version.transaction_version);

    Ok(())
}
```

## Common Use Cases

### 1. Runtime Upgrade Monitor

Detect runtime upgrades on XX Network in real time:

```javascript
async function monitorUpgrades(api) {
  let currentVersion = (await api.rpc.state.getRuntimeVersion()).specVersion.toNumber();
  console.log(`Starting monitor at spec version: ${currentVersion}`);

  const unsub = await api.rpc.chain.subscribeNewHeads(async (header) => {
    const version = await api.rpc.state.getRuntimeVersion(header.hash);
    const newVersion = version.specVersion.toNumber();

    if (newVersion !== currentVersion) {
      console.log(`Runtime upgrade detected! ${currentVersion} -> ${newVersion}`);
      currentVersion = newVersion;
      // Trigger reconnection or metadata refresh
    }
  });

  return unsub;
}
```

### 2. Transaction Construction with Correct Version

Include the correct version fields when constructing signed extrinsics:

```javascript
async function getSigningPayloadInfo(api) {
  const version = await api.rpc.state.getRuntimeVersion();
  const genesisHash = await api.rpc.chain.getBlockHash(0);

  return {
    specVersion: version.specVersion.toNumber(),
    transactionVersion: version.transactionVersion.toNumber(),
    genesisHash: genesisHash.toHex(),
    // These fields are required for signing extrinsics
  };
}
```

### 3. Historical Version Comparison

Compare runtime versions across blocks to identify upgrade boundaries:

```javascript
async function findUpgradeBlock(api, startBlock, endBlock) {
  const startHash = await api.rpc.chain.getBlockHash(startBlock);
  const startVersion = (await api.rpc.state.getRuntimeVersion(startHash)).specVersion.toNumber();

  // Binary search for upgrade block
  let low = startBlock;
  let high = endBlock;

  while (low < high) {
    const mid = Math.floor((low + high) / 2);
    const midHash = await api.rpc.chain.getBlockHash(mid);
    const midVersion = (await api.rpc.state.getRuntimeVersion(midHash)).specVersion.toNumber();

    if (midVersion === startVersion) {
      low = mid + 1;
    } else {
      high = mid;
    }
  }

  console.log(`Runtime upgraded at block #${low}`);
  return low;
}
```

## Related Methods

- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) - Get full runtime metadata for decoding
- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) - Get node software version
- [`chain_subscribeFinalizedHeads`](https://www.dwellir.com/docs/xx-network/chain_subscribeFinalizedHeads) - Subscribe to detect upgrade blocks

---

## state_getStorage - XX Network RPC Method

# state_getStorage - XX Network RPC Method

Returns the SCALE-encoded storage value for a given key on XX Network. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`state_getStorage` is essential for XX Network developers building privacy-preserving applications:

- **Low-Level State Access** -- Read the raw SCALE-encoded value stored under a known key on XX Network
- **Metadata-Aware Tooling** -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- **Historical State Queries** -- Read storage values at a specific block hash to analyze state changes over time
- **Pallet Storage Inspection** -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated

## Best Practices

- Storage keys use pallet-specific encoding -- use `state_getMetadata` to discover key formats
- Handle `null` return values for storage keys that have never been set
- For batch storage reads, use `state_queryStorageAt` for better efficiency
- Cache storage values if querying the same key at the same block height

## Request Parameters

- `key` (`String, required`): Hex-encoded storage key (constructed from pallet name, storage item name, and optional map keys using the appropriate hashing algorithm)
- `blockHash` (`String, optional`): Block hash at which to query storage; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getStorage",
  "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String | null, required`): Hex-encoded SCALE value at the storage key, or null if no value exists at that key

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error: State not available for block"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query the System.Account storage for an account
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": ["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
    "id": 1
  }'

# Query at a specific block hash
# Replace 0xYOUR_RECENT_BLOCK_HASH with a recent finalized hash from chain_getFinalizedHead
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_getStorage",
    "params": [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
      "0xYOUR_RECENT_BLOCK_HASH"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (recommended -- handles key construction and decoding)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Construct a storage key with metadata-aware helpers
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const storageKey = api.query.system.account.key(account);
console.log('Storage key:', storageKey);

// Read the raw SCALE-encoded value with state_getStorage
const rawValue = await api.rpc.state.getStorage(storageKey);
console.log('Raw SCALE value:', rawValue.toHex());

// Historical read at a specific block hash
const blockHash = await api.rpc.chain.getFinalizedHead();
const historicalRaw = await api.rpc.state.getStorage(storageKey, blockHash);
console.log('Historical raw SCALE value:', historicalRaw?.toHex() ?? null);

// Metadata-aware alternative: decode the same key via api.query
const accountInfo = await api.query.system.account(account);
console.log('Decoded free balance:', accountInfo.data.free.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC) with a precomputed storage key
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_getStorage',
    params: ['0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded storage value:', result);
```

```python
import requests

def get_storage(key, block_hash=None):
    params = [key]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_getStorage',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query raw storage with a precomputed key
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...'
value = get_storage(storage_key)
if value:
    print(f'Storage value: {value[:66]}...')
else:
    print('No value at this key')

# Metadata-aware alternative using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')

# High-level query with automatic SCALE decoding
result = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
)

print(f"Nonce: {result.value['nonce']}")
print(f"Free: {result.value['data']['free']}")
print(f"Reserved: {result.value['data']['reserved']}")

# Historical query at a specific block
result_at = substrate.query(
    module='System',
    storage_function='Account',
    params=['5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'],
    block_hash=substrate.rpc_request('chain_getFinalizedHead', [])['result']
)
print(f"Historical free: {result_at.value['data']['free']}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Precomputed storage key for System.Account
    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7\
        b99d880ec681799c0cf30e8886371da9\
        de1e86a9a8c739864cf3cc5ec2bea59f\
        d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;

    match result["result"].as_str() {
        Some(value) => {
            println!("SCALE-encoded value: {}", &value[..66.min(value.len())]);
            // Decode using parity-scale-codec or subxt for typed access
        }
        None => println!("No value at this storage key"),
    }

    // Query at a specific block hash
    let block_hash = "0xYOUR_RECENT_BLOCK_HASH";
    let historical = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_getStorage",
            "params": [storage_key, block_hash],
            "id": 1
        }))
        .send()
        .await?;

    let hist_result: serde_json::Value = historical.json().await?;
    println!("Historical value: {:?}", hist_result["result"]);

    Ok(())
}
```

## Common Use Cases

### 1. Raw Storage Watcher

Query and track changes for a specific storage key over time:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
  let previousValue = null;

  setInterval(async () => {
    const current = await api.rpc.state.getStorage(storageKey);
    const raw = current?.toHex() ?? null;

    if (previousValue !== null && raw !== previousValue) {
      console.log(`Storage value changed: ${previousValue} -> ${raw}`);
    }

    previousValue = raw;
  }, intervalMs);
}
```

### 2. Metadata-Aware Decode

Use a higher-level library to decode the value after you confirm the raw storage key:

```javascript
async function decodeAccountStorage(api, address) {
  const storageKey = api.query.system.account.key(address);
  const raw = await api.rpc.state.getStorage(storageKey);
  const decoded = await api.query.system.account(address);

  return {
    storageKey: storageKey.toHex(),
    raw: raw?.toHex() ?? null,
    decoded: decoded.toJSON()
  };
}
```

### 3. Historical State Comparison

Compare storage values between two blocks to detect state transitions:

```javascript
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
  const [apiAtA, apiAtB] = await Promise.all([
    api.at(blockHashA),
    api.at(blockHashB)
  ]);

  // Navigate the nested query path (e.g., 'system.account')
  const parts = storageQuery.split('.');
  let queryA = apiAtA.query;
  let queryB = apiAtB.query;
  for (const part of parts) {
    queryA = queryA[part];
    queryB = queryB[part];
  }

  const [valueA, valueB] = await Promise.all([
    queryA(...params),
    queryB(...params)
  ]);

  const jsonA = valueA.toJSON();
  const jsonB = valueB.toJSON();

  console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
  console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);

  return { before: jsonA, after: jsonB };
}

// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);
```

## Storage Key Construction

For developers who need to construct storage keys manually (without a high-level library):

| Storage Type   | Key Structure                                                         | Example                                 |
| -------------- | --------------------------------------------------------------------- | --------------------------------------- |
| **Value**      | `xxhash128(Pallet) + xxhash128(Item)`                                 | `Timestamp.Now`                         |
| **Map**        | `xxhash128(Pallet) + xxhash128(Item) + hasher(Key)`                   | `System.Account(accountId)`             |
| **Double Map** | `xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2)` | `Staking.ErasStakers(era, validatorId)` |

Common hashers used in Substrate:

- **Blake2\_128Concat** -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- **Twox64Concat** -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- **Identity** -- Raw key with no hashing (used for already-unique keys)

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/xx-network/state_getKeysPaged) -- Enumerate storage keys matching a prefix (useful for iterating map entries)
- [`state_queryStorageAt`](https://www.dwellir.com/docs/xx-network/state_queryStorageAt) -- Query multiple storage keys at a specific block in a single request
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) -- Get runtime metadata including storage definitions, types, and hashing algorithms
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) -- Call runtime APIs for computed state that is not directly in storage
- `state_subscribeStorage` -- Subscribe to storage changes in real time via WebSocket

---

## state_queryStorageAt - XX Network RPC Method

# state_queryStorageAt - XX Network RPC Method

Queries multiple storage keys at a specific block on XX Network, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`state_queryStorageAt` is essential for XX Network developers building privacy-preserving applications:

- **Consistent State Snapshots** -- Fetch multiple storage values from the same block to ensure data consistency on XX Network
- **Batch Raw Storage Reads** -- Retrieve several known storage keys in one RPC call
- **Indexer and Analytics** -- Build efficient data pipelines by querying all required storage keys at once
- **Historical State Analysis** -- Compare storage state across different blocks for auditing and data analysis

## Best Practices

- Requires an archive node for querying deep historical state
- More efficient than making individual `state_getStorage` calls for multiple keys
- Accepts multiple storage keys in a single request for batch retrieval
- Use block hashes (not numbers) for deterministic historical queries

## Request Parameters

- `keys` (`Array<String>, required`): Array of hex-encoded storage keys to query
- `blockHash` (`String, optional`): Block hash to query at; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_queryStorageAt",
  "params": [
    [
      "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ]
  ],
  "id": 1
}
```

## Response Fields

- `block` (`String, required`): The block hash at which the query was executed
- `changes` (`Array<[String, String|null]>, required`): Array of [key, value] pairs. The value is a hex-encoded SCALE value, or null if the key does not exist

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "block": "0x1a2b3c4d5e6f...",
      "changes": [
        [
          "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
          "0x0100000000000000010000000000000000407a10f35a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]
      ]
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_queryStorageAt",
    "params": [
      [
        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
      ]
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api helpers to construct storage keys
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// High-level: query multiple accounts at once
const accounts = [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
];
const storageKeys = await Promise.all(
  accounts.map((addr) => api.query.system.account.key(addr))
);

const queryResult = await api.rpc.state.queryStorageAt(storageKeys);
console.log('Block:', queryResult[0].block.toHex());
console.log('Changes:', queryResult[0].changes.length);

// Metadata-aware alternative: decode those same accounts at the latest state
const decoded = await api.query.system.account.multi(accounts);
decoded.forEach((info, idx) => {
  console.log(`Decoded account ${accounts[idx]} free balance:`, info.data.free.toString());
});

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_queryStorageAt',
    params: [storageKeys.map((k) => k.toHex())],
    id: 1
  })
});

const { result } = await response.json();
console.log('Queried at block:', result[0].block);
```

```python
import requests

def query_storage_at(keys, block_hash=None):
    params = [keys]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_queryStorageAt',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query System.Account storage for an account
storage_key = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = query_storage_at([storage_key])
print(f"Block: {result[0]['block']}")
for key, value in result[0]['changes']:
    print(f"  Key: {key[:40]}...")
    print(f"  Value: {value[:40] if value else 'null'}...")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
result = substrate.rpc_request('state_queryStorageAt', [[storage_key]])['result']
print(f"Changes: {len(result[0]['changes'])}")
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    let storage_key = "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_queryStorageAt",
            "params": [[storage_key]],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let entries = &result["result"][0];

    println!("Block: {}", entries["block"]);
    if let Some(changes) = entries["changes"].as_array() {
        for change in changes {
            let key = change[0].as_str().unwrap_or("");
            let value = change[1].as_str().unwrap_or("null");
            println!("  Key: {}...", &key[..std::cmp::min(40, key.len())]);
            println!("  Value: {}...", &value[..std::cmp::min(40, value.len())]);
        }
    }

    Ok(())
}
```

## Common Use Cases

### 1. Multi-Key Snapshot

Read multiple storage keys from the same block:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});
```

### 2. Historical State Comparison

Compare storage state between two blocks for auditing:

```javascript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}
```

### 3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

```javascript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/xx-network/state_getStorage) -- Query a single storage key
- [`state_getKeysPaged`](https://www.dwellir.com/docs/xx-network/state_getKeysPaged) -- Enumerate storage keys with pagination
- [`state_call`](https://www.dwellir.com/docs/xx-network/state_call) -- Call a runtime API function
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) -- Get runtime metadata to construct storage keys
- [`chain_getBlockHash`](https://www.dwellir.com/docs/xx-network/chain_getBlockHash) -- Get a block hash by block number for historical queries

---

## system_chain - XX Network RPC Method

# system_chain - XX Network RPC Method

Returns the chain name of the XX Network network. This identifies the specific chain or network the node is connected to (e.g., `"Polkadot"`, `"Kusama"`, `"Westend"`).

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`system_chain` is essential for XX Network developers building privacy-preserving applications:

- **Network Verification** -- Confirm your application is connected to the correct XX Network network before processing transactions
- **Multi-Chain Applications** -- Dynamically identify which Substrate chain you are interacting with in cross-chain or multi-network dApps
- **UI Display** -- Show the connected network name in wallet interfaces and dashboards for secure messaging, private payments, and quantum-resistant cryptography
- **Configuration Validation** -- Verify endpoint configuration matches the expected chain during deployment

## Best Practices

- Cache the chain name at startup -- it does not change during a session
- Use with `system_properties` for complete chain identification (name, token, decimals)
- Chain name is a simple string identifier, not a unique numeric ID
- For multi-chain applications, maintain a mapping of chain names to app configuration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_chain",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The human-readable chain name (e.g., "Polkadot", "Kusama", "Acala")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "XX Network"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_chain",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const chain = await api.rpc.system.chain();
console.log('Connected to chain:', chain.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_chain',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Connected to chain:', result);
```

```python
import requests

def get_chain_name():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_chain',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

chain = get_chain_name()
print(f'Connected to chain: {chain}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
chain = substrate.rpc_request('system_chain', [])['result']
print(f'Connected to chain: {chain}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_chain",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("Connected to chain: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Network Connection Verification

Validate that your application connects to the correct chain before processing any transactions:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function connectAndVerify(endpoint, expectedChain) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const chain = await api.rpc.system.chain();
  const chainName = chain.toString();

  if (chainName !== expectedChain) {
    await api.disconnect();
    throw new Error(
      `Expected "${expectedChain}" but connected to "${chainName}"`
    );
  }

  console.log(`Verified connection to ${chainName}`);
  return api;
}

// Usage
const api = await connectAndVerify('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', 'XX Network');
```

### 2. Multi-Chain Router

Route operations based on detected chain identity:

```javascript
async function getChainConfig(api) {
  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const chainName = chain.toString();
  const configs = {
    Polkadot: { explorer: 'https://polkadot.subscan.io', confirmations: 1 },
    Kusama: { explorer: 'https://kusama.subscan.io', confirmations: 1 },
  };

  const config = configs[chainName] || { explorer: null, confirmations: 1 };

  return {
    name: chainName,
    tokenSymbol: properties.tokenSymbol.toString(),
    tokenDecimals: properties.tokenDecimals.toJSON(),
    ...config
  };
}
```

### 3. Health Check with Chain Identity

Include chain identity in health-check monitoring:

```javascript
async function healthCheck(api) {
  const [chain, name, version] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.name(),
    api.rpc.system.version()
  ]);

  return {
    status: 'healthy',
    chain: chain.toString(),
    nodeImplementation: name.toString(),
    nodeVersion: version.toString(),
    timestamp: new Date().toISOString()
  };
}
```

## Related Methods

- [`system_name`](https://www.dwellir.com/docs/xx-network/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) -- Get the node implementation version
- [`system_properties`](https://www.dwellir.com/docs/xx-network/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/xx-network/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/xx-network/rpc_methods) -- List all available RPC methods

---

## system_health - XX Network RPC Method

# system_health - XX Network RPC Method

Returns the health status of the XX Network node, including peer count, sync state, and whether the node expects to have peers.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`system_health` is essential for XX Network developers building privacy-preserving applications:

- **Health Checks** - Monitor node availability and readiness before routing traffic on XX Network
- **Load Balancing** - Route requests only to healthy, fully synced nodes for secure messaging, private payments, and quantum-resistant cryptography
- **Sync Status** - Verify a node is caught up before trusting its state queries
- **Infrastructure Alerts** - Trigger alerts when peers drop or sync stalls

## Best Practices

- Call at application startup before processing any transactions
- If `isSyncing` is `true`, delay all transaction operations until it returns `false`
- Low `peers` count may indicate network connectivity issues
- Combine with `system_chain` and `system_version` for a complete node health check

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_health",
  "params": [],
  "id": 1
}
```

## Response Fields

- `peers` (`Number, required`): Number of connected peers
- `isSyncing` (`Boolean, required`): true if the node is still syncing with the network
- `shouldHavePeers` (`Boolean, required`): true if the node is expected to have peers (false for local dev chains)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "peers": 42,
    "isSyncing": false,
    "shouldHavePeers": true
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_health",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const health = await api.rpc.system.health();
console.log('Peers:', health.peers.toNumber());
console.log('Is syncing:', health.isSyncing.isTrue);
console.log('Should have peers:', health.shouldHavePeers.isTrue);

const isHealthy = !health.isSyncing.isTrue && health.peers.toNumber() > 0;
console.log('Node healthy:', isHealthy);

await api.disconnect();
```

```python
import requests

def get_health():
    url = 'https://api-xxnetwork.dwellir.com/YOUR_API_KEY'

    payload = {
        'jsonrpc': '2.0',
        'method': 'system_health',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"RPC Error: {result['error']}")

    return result['result']

health = get_health()
print(f"Peers: {health['peers']}")
print(f"Syncing: {health['isSyncing']}")
print(f"Should have peers: {health['shouldHavePeers']}")

is_healthy = not health['isSyncing'] and health['peers'] > 0
print(f"Node healthy: {is_healthy}")
```

```rust
use subxt::{OnlineClient, PolkadotConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "wss://api-xxnetwork.dwellir.com/YOUR_API_KEY"
    ).await?;

    let health = api.rpc()
        .system_health()
        .await?;

    println!("Peers: {}", health.peers);
    println!("Is syncing: {}", health.is_syncing);
    println!("Should have peers: {}", health.should_have_peers);

    let is_healthy = !health.is_syncing && health.peers > 0;
    println!("Node healthy: {}", is_healthy);

    Ok(())
}
```

## Common Use Cases

### 1. Readiness Probe for Kubernetes

Use as a health check endpoint for container orchestration on XX Network:

```javascript
import express from 'express';
import { ApiPromise, WsProvider } from '@polkadot/api';

const app = express();
const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

app.get('/healthz', async (req, res) => {
  try {
    const health = await api.rpc.system.health();
    const isReady = !health.isSyncing.isTrue && health.peers.toNumber() > 0;

    if (isReady) {
      res.status(200).json({ status: 'healthy', peers: health.peers.toNumber() });
    } else {
      res.status(503).json({
        status: 'not ready',
        syncing: health.isSyncing.isTrue,
        peers: health.peers.toNumber()
      });
    }
  } catch (error) {
    res.status(503).json({ status: 'unreachable', error: error.message });
  }
});
```

### 2. Multi-Node Load Balancer

Route traffic only to healthy XX Network nodes:

```javascript
async function selectHealthyNode(endpoints) {
  const results = await Promise.allSettled(
    endpoints.map(async (endpoint) => {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'system_health',
          params: [],
          id: 1
        })
      });

      const { result } = await response.json();
      return { endpoint, ...result };
    })
  );

  const healthy = results
    .filter(r => r.status === 'fulfilled' && !r.value.isSyncing)
    .map(r => r.value)
    .sort((a, b) => b.peers - a.peers);

  return healthy.length > 0 ? healthy[0].endpoint : null;
}
```

### 3. Continuous Health Monitor

Periodically check node health and alert on degradation:

```python
import requests
import time

def monitor_health(endpoint, interval=30, min_peers=5):
    while True:
        try:
            payload = {
                'jsonrpc': '2.0',
                'method': 'system_health',
                'params': [],
                'id': 1
            }

            response = requests.post(endpoint, json=payload, timeout=5)
            health = response.json()['result']

            peers = health['peers']
            syncing = health['isSyncing']

            if syncing:
                print(f'WARNING: Node is syncing (peers: {peers})')
            elif peers < min_peers:
                print(f'WARNING: Low peer count: {peers}')
            else:
                print(f'OK: peers={peers}, syncing={syncing}')

        except Exception as e:
            print(f'ERROR: Node unreachable - {e}')

        time.sleep(interval)

monitor_health('https://api-xxnetwork.dwellir.com/YOUR_API_KEY')
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) - Get node software version
- [`system_chain`](https://www.dwellir.com/docs/xx-network/system_chain) - Get chain name
- `system_syncState` - Get detailed sync progress
- `system_peers` - Get detailed peer information

---

## system_name - XX Network RPC Method

# system_name - XX Network RPC Method

Returns the node implementation name on XX Network. This identifies the client software running the node (e.g., `"Parity Polkadot"`, `"Substrate Node"`, `"Astar Collator"`).

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`system_name` is essential for XX Network developers building privacy-preserving applications:

- **Client Identification** -- Determine which Substrate client implementation your node is running (useful when multiple implementations exist)
- **Infrastructure Monitoring** -- Track client types across your validator or collator fleet on XX Network
- **Bug Reports and Diagnostics** -- Include client implementation details when reporting issues for secure messaging, private payments, and quantum-resistant cryptography
- **Compatibility Checks** -- Verify that the node implementation supports features required by your application

## Best Practices

- Provides client implementation info -- equivalent to `web3_clientVersion` on EVM chains
- Include this output in bug reports when troubleshooting node behavior
- Different client implementations (Substrate, Polkadot SDK, Cumulus) return different names
- Use with `system_version` for the complete software identity

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_name",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation name (e.g., "Parity Polkadot", "Substrate Node")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Parity Polkadot"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_name",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const name = await api.rpc.system.name();
console.log('XX Network node implementation:', name.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_name',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('XX Network node implementation:', result);
```

```python
import requests

def get_node_name():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_name',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

name = get_node_name()
print(f'XX Network node implementation: {name}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
name = substrate.rpc_request('system_name', [])['result']
print(f'XX Network node implementation: {name}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_name",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("XX Network node implementation: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Full Node Identity Report

Gather complete node identity details in a single call:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNodeIdentity(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [name, version, chain] = await Promise.all([
    api.rpc.system.name(),
    api.rpc.system.version(),
    api.rpc.system.chain()
  ]);

  const identity = {
    implementation: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    endpoint
  };

  await api.disconnect();
  return identity;
}

// Example output:
// { implementation: "Parity Polkadot", version: "0.9.43-ba6af17", chain: "Polkadot", endpoint: "..." }
```

### 2. Infrastructure Audit Across Nodes

Audit client implementations across a fleet of XX Network nodes:

```javascript
async function auditFleetClients(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      try {
        const provider = new WsProvider(endpoint);
        const api = await ApiPromise.create({ provider });
        const name = await api.rpc.system.name();
        const version = await api.rpc.system.version();
        await api.disconnect();
        return { endpoint, client: name.toString(), version: version.toString(), status: 'ok' };
      } catch (error) {
        return { endpoint, client: null, version: null, status: 'unreachable' };
      }
    })
  );

  // Group by client implementation
  const byClient = {};
  for (const node of results) {
    if (node.client) {
      byClient[node.client] = byClient[node.client] || [];
      byClient[node.client].push(node);
    }
  }

  console.log('Client distribution:', Object.keys(byClient).map(
    (k) => `${k}: ${byClient[k].length} nodes`
  ));

  return results;
}
```

### 3. Connection Health Check with Client Info

Include client implementation in health-check responses:

```javascript
async function healthCheckWithClientInfo(api) {
  try {
    const name = await api.rpc.system.name();
    const version = await api.rpc.system.version();
    const chain = await api.rpc.system.chain();

    return {
      healthy: true,
      client: `${name.toString()} v${version.toString()}`,
      chain: chain.toString(),
      checkedAt: new Date().toISOString()
    };
  } catch (error) {
    return {
      healthy: false,
      error: error.message,
      checkedAt: new Date().toISOString()
    };
  }
}
```

## Related Methods

- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) -- Get the node implementation version
- [`system_chain`](https://www.dwellir.com/docs/xx-network/system_chain) -- Get the chain name
- [`system_properties`](https://www.dwellir.com/docs/xx-network/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/xx-network/state_getRuntimeVersion) -- Get the on-chain runtime version
- [`rpc_methods`](https://www.dwellir.com/docs/xx-network/rpc_methods) -- List all available RPC methods

---

## system_properties - XX Network RPC Method

# system_properties - XX Network RPC Method

Returns the chain-specific properties for XX Network, including the native token symbol, token decimals, and the address-format prefix when the chain exposes one. This information is critical for correctly formatting balances, validating addresses, and configuring wallets.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`system_properties` is essential for XX Network developers building privacy-preserving applications:

- **Token Formatting** -- Get the correct decimals and symbol to display human-readable balances on XX Network
- **Address Validation** -- Retrieve the SS58 prefix to encode and validate addresses for secure messaging, private payments, and quantum-resistant cryptography
- **Wallet and dApp Configuration** -- Dynamically configure your UI with the correct token symbol, decimals, and address format
- **Multi-Chain Support** -- Automatically adapt your application to different Substrate chains without hardcoding properties

## Best Practices

- `tokenDecimals` determines on-chain amount display (verified: Polkadot returns 10 decimals for DOT)
- `tokenSymbol` provides the native token ticker for UI display
- `ss58Format` is the address encoding prefix for this chain (0 for Polkadot, 2 for Kusama)
- Cache these properties at startup -- they do not change without a chain migration

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_properties",
  "params": [],
  "id": 1
}
```

## Response Fields

- `ss58Format or SS58Prefix` (`Number, required`): The SS58 address format prefix used by this chain, when the chain exposes one
- `tokenDecimals` (`Number | Array<Number>, required`): Number of decimal places for the native token, or an array for multi-token chains
- `tokenSymbol` (`String | Array<String>, required`): Native token symbol, or an array for multi-token chains

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ss58Format": 42,
    "tokenDecimals": 9,
    "tokenSymbol": "TOKEN"
  }
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_properties",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const properties = await api.rpc.system.properties();

const raw = properties.toJSON();
const tokenSymbol = Array.isArray(raw.tokenSymbol) ? raw.tokenSymbol : [raw.tokenSymbol];
const tokenDecimals = Array.isArray(raw.tokenDecimals) ? raw.tokenDecimals : [raw.tokenDecimals];
const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

console.log('Token symbol:', tokenSymbol);
console.log('Token decimals:', tokenDecimals);
console.log('SS58 format:', ss58Format ?? 'not exposed');

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_properties',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Properties:', result);
```

```python
import requests

def get_chain_properties():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_properties',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

props = get_chain_properties()
token_symbol = props['tokenSymbol']
token_decimals = props['tokenDecimals']
ss58_format = props.get('ss58Format', props.get('SS58Prefix'))

print(f"Token: {token_symbol}")
print(f"Decimals: {token_decimals}")
print(f"SS58 Format: {ss58_format if ss58_format is not None else 'not exposed'}")

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
props = substrate.properties
print(f"Token: {props.get('tokenSymbol')}")
print(f"Decimals: {props.get('tokenDecimals')}")
print(f"SS58 Format: {props.get('ss58Format', props.get('SS58Prefix', 'not exposed'))}")
```

```rust
use serde_json::json;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ChainProperties {
    #[serde(alias = "SS58Prefix")]
    ss58_format: Option<u16>,
    token_decimals: Option<serde_json::Value>,
    token_symbol: Option<serde_json::Value>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_properties",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    let props: ChainProperties = serde_json::from_value(result["result"].clone())?;

    println!("SS58 Format: {:?}", props.ss58_format);
    println!("Token Decimals: {:?}", props.token_decimals);
    println!("Token Symbol: {:?}", props.token_symbol);
    Ok(())
}
```

## Common Use Cases

### 1. Human-Readable Balance Formatting

Format raw on-chain balances into human-readable token amounts:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';

async function formatBalance(api, rawBalance) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const decimalsRaw = raw.tokenDecimals;
  const symbolRaw = raw.tokenSymbol;
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw[0] : decimalsRaw;
  const symbol = Array.isArray(symbolRaw) ? symbolRaw[0] : symbolRaw;

  const divisor = new BN(10).pow(new BN(decimals));
  const whole = new BN(rawBalance).div(divisor);
  const fractional = new BN(rawBalance).mod(divisor).toString().padStart(decimals, '0');

  return `${whole}.${fractional.slice(0, 4)} ${symbol}`;
}

// Example output depends on the chain's live token symbol and decimals.
```

### 2. Dynamic Wallet Configuration

Auto-configure your wallet or dApp based on chain properties:

```javascript
async function configureWallet(endpoint) {
  const provider = new WsProvider(endpoint);
  const api = await ApiPromise.create({ provider });

  const [chain, properties] = await Promise.all([
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  const raw = properties.toJSON();
  const symbolsRaw = raw.tokenSymbol;
  const decimalsRaw = raw.tokenDecimals;
  const symbols = Array.isArray(symbolsRaw) ? symbolsRaw : [symbolsRaw];
  const decimals = Array.isArray(decimalsRaw) ? decimalsRaw : [decimalsRaw];
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix ?? null;

  const config = {
    chainName: chain.toString(),
    ss58Format,
    tokens: symbols.map((symbol, idx) => ({
      symbol,
      decimals: decimals[idx] ?? decimals[0],
    }))
  };

  console.log('Wallet configured for:', config.chainName);
  console.log('Native token:', config.tokens[0].symbol, `(${config.tokens[0].decimals} decimals)`);
  console.log('Address format SS58:', config.ss58Format ?? 'not exposed');

  await api.disconnect();
  return config;
}
```

### 3. SS58 Address Encoding and Validation

Use the SS58 prefix to properly encode addresses for the target chain:

```javascript
import { encodeAddress, decodeAddress } from '@polkadot/util-crypto';

async function formatAddressForChain(api, genericAddress) {
  const properties = await api.rpc.system.properties();
  const raw = properties.toJSON();
  const ss58Format = raw.ss58Format ?? raw.SS58Prefix;

  if (ss58Format == null) {
    throw new Error('This chain does not expose an SS58 prefix through system_properties.');
  }

  // Convert any SS58 address to this chain's format
  const publicKey = decodeAddress(genericAddress);
  const chainAddress = encodeAddress(publicKey, ss58Format);

  console.log(`Address on ${ss58Format}: ${chainAddress}`);
  return chainAddress;
}
```

ze scalar vs array values and fall back to `SS58Prefix` when `ss58Format` is absent |

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/xx-network/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/xx-network/system_name) -- Get the node implementation name
- [`system_version`](https://www.dwellir.com/docs/xx-network/system_version) -- Get the node implementation version
- [`state_getMetadata`](https://www.dwellir.com/docs/xx-network/state_getMetadata) -- Get full runtime metadata including pallet definitions
- [`rpc_methods`](https://www.dwellir.com/docs/xx-network/rpc_methods) -- List all available RPC methods

---

## system_version - XX Network RPC Method

# system_version - XX Network RPC Method

Returns the node implementation version string on XX Network. This version reflects the client software version (e.g., `0.9.43-ba6af1743a0`), not the on-chain runtime version.

> **Why XX Network?** Build on a privacy-focused decentralized messaging and payment platform with quantum-resistant cryptography and metadata privacy through cMix.

## When to Use This Method

`system_version` is essential for XX Network developers building privacy-preserving applications:

- **Compatibility Checking** -- Verify the node client version supports the features your application requires on XX Network
- **Upgrade Monitoring** -- Track node software versions across your validator or collator fleet after runtime upgrades
- **Diagnostics and Debugging** -- Include version information in bug reports and support requests for secure messaging, private payments, and quantum-resistant cryptography
- **Multi-Node Management** -- Ensure all nodes in your infrastructure are running consistent versions

## Best Practices

- Check the runtime version before using version-specific Substrate APIs
- Track version changes during runtime upgrades to detect compatibility issues
- Use with `system_chain` and `system_properties` for full network context
- Different nodes on the same network should return the same version (unless upgrading)

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "system_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The node implementation version string (e.g., "0.9.43-ba6af1743a0")

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0.9.43-ba6af1743a0"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
curl -X POST https://api-xxnetwork.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "system_version",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-xxnetwork.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

const version = await api.rpc.system.version();
console.log('XX Network node version:', version.toString());

await api.disconnect();

// Using fetch (HTTP JSON-RPC)
const response = await fetch('https://api-xxnetwork.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'system_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('XX Network node version:', result);
```

```python
import requests

def get_system_version():
    response = requests.post(
        'https://api-xxnetwork.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'system_version',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

version = get_system_version()
print(f'XX Network node version: {version}')

# Using substrate-interface
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-xxnetwork.dwellir.com/YOUR_API_KEY')
version = substrate.rpc_request('system_version', [])['result']
print(f'XX Network node version: {version}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post("https://api-xxnetwork.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "system_version",
            "params": [],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("XX Network node version: {}", result["result"]);
    Ok(())
}
```

## Common Use Cases

### 1. Node Fleet Version Monitoring

Track version consistency across multiple XX Network nodes:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function checkFleetVersions(endpoints) {
  const versions = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new WsProvider(endpoint);
      const api = await ApiPromise.create({ provider });
      const version = await api.rpc.system.version();
      const name = await api.rpc.system.name();
      await api.disconnect();
      return { endpoint, version: version.toString(), name: name.toString() };
    })
  );

  const unique = new Set(versions.map((v) => v.version));
  if (unique.size > 1) {
    console.warn('Version mismatch detected across fleet!');
  }

  versions.forEach((v) => {
    console.log(`${v.endpoint}: ${v.name} v${v.version}`);
  });
}
```

### 2. Pre-Upgrade Compatibility Check

Verify node version before executing operations:

```javascript
async function ensureMinVersion(api, minVersion) {
  const version = await api.rpc.system.version();
  const versionStr = version.toString();
  const [major, minor, patch] = versionStr.split('-')[0].split('.').map(Number);
  const [minMajor, minMinor, minPatch] = minVersion.split('.').map(Number);

  if (
    major < minMajor ||
    (major === minMajor && minor < minMinor) ||
    (major === minMajor && minor === minMinor && patch < minPatch)
  ) {
    throw new Error(
      `Node version ${versionStr} is below minimum ${minVersion}`
    );
  }

  console.log(`Node version ${versionStr} meets minimum ${minVersion}`);
  return true;
}
```

### 3. Node Identity Dashboard

Gather full node identity information:

```javascript
async function getNodeIdentity(api) {
  const [version, name, chain, properties] = await Promise.all([
    api.rpc.system.version(),
    api.rpc.system.name(),
    api.rpc.system.chain(),
    api.rpc.system.properties()
  ]);

  return {
    client: name.toString(),
    version: version.toString(),
    chain: chain.toString(),
    tokenSymbol: properties.tokenSymbol.toString(),
    ss58Format: properties.ss58Format.toString()
  };
}
```

## Related Methods

- [`system_chain`](https://www.dwellir.com/docs/xx-network/system_chain) -- Get the chain name
- [`system_name`](https://www.dwellir.com/docs/xx-network/system_name) -- Get the node implementation name
- [`system_properties`](https://www.dwellir.com/docs/xx-network/system_properties) -- Get chain properties (token symbol, decimals, SS58 format)
- [`state_getRuntimeVersion`](https://www.dwellir.com/docs/xx-network/state_getRuntimeVersion) -- Get the on-chain runtime version (spec version, impl version)
- [`rpc_methods`](https://www.dwellir.com/docs/xx-network/rpc_methods) -- List all available RPC methods

---

## ZetaChain - Omnichain Smart Contract Platform

# ZetaChain - Omnichain Smart Contract Platform

## ZetaChain RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where ZetaChain supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## What is ZetaChain?

**ZetaChain** is the foundational layer for universal blockchain interoperability, enabling omnichain smart contracts and messaging between any blockchain. As a Proof-of-Stake blockchain built on Cosmos SDK and Tendermint consensus, ZetaChain connects all blockchains, including Bitcoin, Ethereum, and other chains without smart contracts.

### Key Features

- \*\* Universal Connectivity\*\* - Connect to any blockchain, including Bitcoin and non-smart contract chains
- \*\* Omnichain Smart Contracts\*\* - Deploy contracts that can read and write to multiple chains
- \*\* Native Cross-Chain Swaps\*\* - Swap assets across chains without wrapped tokens
- \*\* Decentralized Security\*\* - Secured by a decentralized network of validators
- \*\* High Performance\*\* - Fast finality with 6-second block times
- \*\* EVM Compatible\*\* - Full Ethereum compatibility for easy dApp migration

## Why Choose ZetaChain?

### For Cross-Chain Developers

ZetaChain revolutionizes cross-chain development with its unique omnichain smart contract capability:

- **Single Contract, Multiple Chains** - Write once, interact with all chains
- **Native Asset Support** - Handle native tokens without wrapping
- **Simplified Architecture** - No bridges or wrapped tokens needed
- **Universal Messaging** - Send messages and data between any chains

### For DeFi Builders

Build truly interoperable DeFi applications:

- **Cross-Chain Liquidity** - Access liquidity from multiple chains
- **Omnichain DEXs** - Trade assets across chains seamlessly
- **Multi-Chain Yield** - Optimize yields across different blockchains
- **Universal Wallets** - One address for all chains

### For NFT Projects

Create omnichain NFT experiences:

- **Cross-Chain NFTs** - NFTs that exist across multiple chains
- **Multi-Chain Marketplaces** - Buy and sell NFTs from any chain
- **Interoperable Gaming** - Game assets usable across different chains

## Quick Start with ZetaChain

Connect to ZetaChain in seconds with Dwellir's optimized endpoints:

## Network Information

| Parameter    | Value          | Details |
| ------------ | -------------- | ------- |
| Chain ID     | 7000 (0x1b58)  |         |
| Native Token | ZETA           |         |
| Block Time   | 6 seconds      |         |
| Consensus    | Tendermint BFT |         |

## Installation & Setup

Ethers.js v6
Web3.js
Viem
Python

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to ZetaChain mainnet
const provider = new JsonRpcProvider(
  'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Verify connection to ZetaChain (Chain ID: 7000)
const network = await provider.getNetwork();
console.log('Connected to ZetaChain:', network.chainId === 7000n);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query ZETA balance
const balance = await provider.getBalance('0x...');
console.log('ZETA Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to ZetaChain mainnet
const web3 = new Web3(
  'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection (should be 7000)
const chainId = await web3.eth.getChainId();
console.log('Connected to ZetaChain:', chainId === 7000);

// Get current gas price in ZETA
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);

// Check ZETA balance
const balance = await web3.eth.getBalance('0x...');
console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'ZETA');
```

```typescript
import { createPublicClient, http } from 'viem';
import { zetachain } from 'viem/chains';

// Create a public client for ZetaChain
const client = createPublicClient({
  chain: {
    ...zetachain,
    rpcUrls: {
      default: {
        http: ['https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY']
      }
    }
  },
  transport: http()
});

// Get the latest block number
const blockNumber = await client.getBlockNumber();
console.log('Latest block:', blockNumber);

// Read ZETA balance
const balance = await client.getBalance({
  address: '0x...'
});
console.log('Balance:', balance);
```

```python
from web3 import Web3

# Connect to ZetaChain mainnet
w3 = Web3(Web3.HTTPProvider(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'
))

# Verify connection and chain ID (7000)
if w3.is_connected():
    chain_id = w3.eth.chain_id
    print(f"Connected to ZetaChain (Chain ID: {chain_id})")

# Get latest block
block_number = w3.eth.block_number
print(f"Latest block: {block_number}")

# Check ZETA balance
address = '0x...'
balance = w3.eth.get_balance(address)
print(f"Balance: {w3.from_wei(balance, 'ether')} ZETA")
```

## API Reference

## Omnichain Smart Contracts

ZetaChain's unique omnichain smart contracts can interact with multiple blockchains:

```solidity
// Example: Omnichain DEX Contract
pragma solidity 0.8.7;

import "@zetachain/protocol-contracts/contracts/zevm/SystemContract.sol";
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IZRC20.sol";

contract OmnichainDEX {
    SystemContract public systemContract;

    constructor(address systemContractAddress) {
        systemContract = SystemContract(systemContractAddress);
    }

    // Swap tokens across any chain
    function crossChainSwap(
        address zrc20From,
        address zrc20To,
        uint256 amount,
        bytes calldata recipient
    ) external {
        // Transfer from user
        IZRC20(zrc20From).transferFrom(msg.sender, address(this), amount);

        // Perform swap logic
        uint256 amountOut = calculateSwapAmount(zrc20From, zrc20To, amount);

        // Send to recipient on destination chain
        IZRC20(zrc20To).withdraw(recipient, amountOut);
    }
}
```

## Cross-Chain Messaging

Send messages between any blockchains:

```javascript
// Send cross-chain message from Ethereum to Bitcoin
const connector = new ethers.Contract(connectorAddress, connectorABI, signer);

const tx = await connector.send({
    destinationChainId: "18332", // Bitcoin testnet
    destinationAddress: bitcoinAddress,
    destinationGasLimit: 100000,
    message: ethers.utils.defaultAbiCoder.encode(
        ["string"],
        ["Hello from Ethereum!"]
    ),
    zetaValueAndGas: ethers.utils.parseEther("0.1"),
    zetaParams: "0x"
});

console.log('Cross-chain message sent:', tx.hash);
```

## Available Methods

ZetaChain supports all standard Ethereum JSON-RPC methods:

### Core Methods

- **[eth\_blockNumber](https://www.dwellir.com/docs/zetachain/eth_blockNumber)** - Get the latest block number
- **[eth\_call](https://www.dwellir.com/docs/zetachain/eth_call)** - Execute a smart contract call
- **[eth\_chainId](https://www.dwellir.com/docs/zetachain/eth_chainId)** - Get the chain ID (7000)
- **[eth\_getBalance](https://www.dwellir.com/docs/zetachain/eth_getBalance)** - Query account balance

### Transaction Methods

- **[eth\_sendRawTransaction](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction)** - Send signed transactions
- **[eth\_getTransactionByHash](https://www.dwellir.com/docs/zetachain/eth_getTransactionByHash)** - Get transaction details
- **[eth\_getTransactionReceipt](https://www.dwellir.com/docs/zetachain/eth_getTransactionReceipt)** - Get transaction receipt
- **[eth\_estimateGas](https://www.dwellir.com/docs/zetachain/eth_estimateGas)** - Estimate gas for transactions

### Block Methods

- **[eth\_getBlockByNumber](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber)** - Get block by number
- **[eth\_getBlockByHash](https://www.dwellir.com/docs/zetachain/eth_getBlockByHash)** - Get block by hash

### Smart Contract Methods

- **[eth\_getCode](https://www.dwellir.com/docs/zetachain/eth_getCode)** - Get contract bytecode
- **[eth\_getStorageAt](https://www.dwellir.com/docs/zetachain/eth_getStorageAt)** - Read contract storage

### Event Methods

- **[eth\_getLogs](https://www.dwellir.com/docs/zetachain/eth_getLogs)** - Query event logs
- **`eth_newFilter`** - Create event filter (documentation coming soon)

## Rate Limits & Performance

### Endpoint Performance

- **Throughput**: 10,000+ requests/second
- **Latency**: < 50ms average response time
- **Uptime**: 99.95% SLA guarantee
- **Geographic Distribution**: Global edge locations

### Rate Limiting Tiers

| Tier             | Requests/Second | Monthly Requests | Support        |
| ---------------- | --------------- | ---------------- | -------------- |
| **Free**         | 25              | 1M               | Community      |
| **Developer**    | 100             | 10M              | Email          |
| **Professional** | 500             | 100M             | Priority       |
| **Enterprise**   | Custom          | Unlimited        | 24/7 Dedicated |

## Developer Resources

### Official Documentation

- **[ZetaChain Docs](https://docs.zetachain.com)** - Official documentation
- **[GitHub](https://github.com/zeta-chain)** - Source code and examples
- **[Explorer](https://explorer.zetachain.com)** - Block explorer

### SDK & Tools

- **[@zetachain/toolkit](https://www.npmjs.com/package/@zetachain/toolkit)** - JavaScript SDK
- **[@zetachain/protocol-contracts](https://www.npmjs.com/package/@zetachain/protocol-contracts)** - Smart contract interfaces
- **[Hardhat Template](https://github.com/zeta-chain/template)** - Starter template

### Community & Support

- **[Discord](https://discord.gg/zetachain)** - Developer community
- **[Twitter](https://twitter.com/zetablockchain)** - Latest updates
- **[Telegram](https://t.me/zetachainofficial)** - Community chat

## Best Practices

### 1. **Connection Management**

```javascript
// Implement retry logic for resilience
async function createProvider() {
  const provider = new ethers.JsonRpcProvider(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'
  );

  // Set custom timeout
  provider._getConnection().timeout = 10000;

  // Verify connection
  try {
    await provider.getNetwork();
    return provider;
  } catch (error) {
    console.error('Connection failed, retrying...');
    await new Promise(r => setTimeout(r, 1000));
    return createProvider();
  }
}
```

### 2. **Gas Optimization**

```javascript
// Optimize gas for cross-chain transactions
async function estimateCrossChainGas(contract, method, params) {
  // Get current gas price
  const gasPrice = await provider.getGasPrice();

  // Estimate gas with buffer for cross-chain
  const estimatedGas = await contract.estimateGas[method](https://www.dwellir.com/docs/...params);
  const gasLimit = estimatedGas.mul(120).div(100); // 20% buffer

  return {
    gasLimit,
    gasPrice: gasPrice.mul(110).div(100) // 10% above current
  };
}
```

### 3. **Event Monitoring**

```javascript
// Monitor cross-chain events efficiently
function watchCrossChainEvents(contract) {
  const filter = contract.filters.CrossChainCall();

  contract.on(filter, (from, to, amount, destinationChain, event) => {
    console.log(`Cross-chain transfer: ${from} → ${to}`);
    console.log(`Amount: ${amount}, Chain: ${destinationChain}`);
    console.log(`Transaction: ${event.transactionHash}`);
  });
}
```

## Security Considerations

### Cross-Chain Security

- Always validate destination addresses
- Implement proper access controls
- Use time locks for large transfers
- Monitor cross-chain message status

### Smart Contract Best Practices

```solidity
// Secure cross-chain transfer
modifier validateCrossChain(uint256 chainId) {
    require(
        systemContract.isValidChainId(chainId),
        "Invalid destination chain"
    );
    _;
}

function secureCrossChainTransfer(
    uint256 destinationChainId,
    bytes calldata recipient,
    uint256 amount
) external validateCrossChain(destinationChainId) {
    // Implementation
}
```

***

## Need Help?

**Email**: <support@dwellir.com>
**Discord**: [Join our community](https://discord.gg/dwellir)
**More Docs**: [dwellir.com/docs](https://www.dwellir.com/docs)

Start building omnichain dApps with ZetaChain today!

---

## debug_traceBlock - Zetachain RPC Method

# debug_traceBlock - Zetachain RPC Method

Traces all transactions in a block on Zetachain by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Zetachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Zetachain
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Zetachain:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Zetachain blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zetachain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zetachain/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Zetachain RPC Method

# debug_traceBlockByHash - Zetachain RPC Method

Traces all transactions in a block on Zetachain identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Zetachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Zetachain
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Zetachain:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Zetachain:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

Zetachain |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32002 | Resource unavailable | Node is syncing or the requested block is not yet available |

```javascript
async function safeTraceBlockByHash(provider, blockHash, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByHash', [blockHash, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByHash not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockHash} not found - verify the hash is correct`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByHash', [
        blockHash,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/zetachain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zetachain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zetachain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zetachain/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Zetachain RPC Method

# debug_traceBlockByNumber - Zetachain RPC Method

Traces all transactions in a block on Zetachain identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Zetachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Zetachain execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Zetachain:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Zetachain:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

Zetachain - it may be in the future |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32602 | Invalid params | Check that the block number is a valid hex string or tag |

```javascript
async function safeTraceBlockByNumber(provider, blockNumber, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByNumber', [blockNumber, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByNumber not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockNumber} not found on Zetachain`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByNumber', [
        blockNumber,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/zetachain/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zetachain/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zetachain/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Zetachain RPC Method

# debug_traceCall - Zetachain RPC Method

Traces a call on Zetachain without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Zetachain - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Zetachain
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "data": "0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
        "data": "0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
        "data": "0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    data: '0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    data: '0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    'data': '0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
        "data": "0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Zetachain to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Zetachain:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Zetachain:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/zetachain/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zetachain/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Zetachain RPC Method

# debug_traceTransaction - Zetachain RPC Method

Traces a transaction execution on Zetachain by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Zetachain
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/zetachain/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zetachain/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Zetachain RPC Method

# eth_accounts - Zetachain RPC Method

Returns a list of addresses owned by the client on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/zetachain/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/zetachain/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Zetachain RPC Method

# eth_blockNumber - Zetachain RPC Method

Returns the number of the most recent block on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_blockNumber` is fundamental for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Syncing Applications** - Keep your dApp in sync with the latest Zetachain blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Zetachain block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Zetachain block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Zetachain block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Zetachain block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zetachain block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Zetachain:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Zetachain:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Zetachain node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zetachain/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/zetachain/eth_syncing) - Check if node is still syncing

---

## eth_call - Zetachain RPC Method

# eth_call - Zetachain RPC Method

Executes a new message call immediately without creating a transaction on Zetachain. Used for reading smart contract state.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_call` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Zetachain
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';
const walletAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Zetachain. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Zetachain
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Zetachain

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "data": "0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "data": "0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    data := common.FromHex("0x70a082310000000000000000000000005F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Zetachain RPC Method

# eth_chainId - Zetachain RPC Method

Returns the chain ID used for transaction signing on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_chainId` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/zetachain/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/zetachain/eth_syncing) - Check sync status

---

## eth_coinbase - Zetachain RPC Method

# eth_coinbase - Zetachain RPC Method

Checks the legacy `eth_coinbase` compatibility method on Zetachain. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Zetachain coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Zetachain coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Zetachain coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Zetachain coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Zetachain coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Zetachain nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/zetachain/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/zetachain/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/zetachain/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Zetachain RPC Method

# eth_estimateGas - Zetachain RPC Method

Estimates the gas necessary to execute a transaction on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Zetachain
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Zetachain.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Zetachain may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zetachain/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - Zetachain RPC Method

# eth_feeHistory - Zetachain RPC Method

Returns historical gas fee data on Zetachain, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Zetachain without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Zetachain.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Zetachain) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zetachain/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/zetachain/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Zetachain RPC Method

# eth_gasPrice - Zetachain RPC Method

Returns the current gas price on Zetachain in wei.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Zetachain
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Zetachain. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Zetachain, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Zetachain: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Zetachain supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/zetachain/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/zetachain/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Zetachain RPC Method

# eth_getBalance - Zetachain RPC Method

Returns the balance of a given address on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getBalance` is fundamental for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Zetachain
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Zetachain
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Zetachain. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Zetachain`);
  return balance;
}

displayBalance('0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Zetachain at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Zetachain')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Zetachain')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Zetachain.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/zetachain/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/zetachain/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Zetachain RPC Method

# eth_getBlockByHash - Zetachain RPC Method

Returns information about a block by hash on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getBlockByHash` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Zetachain
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Zetachain.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Zetachain.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Zetachain RPC Method

# eth_getBlockByNumber - Zetachain RPC Method

Returns information about a block by block number on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getBlockByNumber` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Zetachain
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x1c062dc4e905e15e9c1099a63c36a1c6fd5f0a6d45334d2e6c4eec3f668bde5f",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Zetachain with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Zetachain. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zetachain/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zetachain/eth_getTransactionByHash) - Get transaction details

---

## eth_getCode - Zetachain RPC Method

# eth_getCode - Zetachain RPC Method

Returns the bytecode at a given address on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getCode` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Zetachain
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Zetachain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Zetachain:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/zetachain/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/zetachain/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Zetachain RPC Method

# eth_getFilterChanges - Zetachain RPC Method

Polls a filter on Zetachain for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getFilterChanges` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Zetachain
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Zetachain:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zetachain/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zetachain/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zetachain/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zetachain/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/zetachain/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Zetachain RPC Method

# eth_getFilterLogs - Zetachain RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Zetachain. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getFilterLogs` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Zetachain
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zetachain/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/zetachain/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zetachain/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Zetachain RPC Method

# eth_getLogs - Zetachain RPC Method

Returns an array of all logs matching a given filter object on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Zetachain for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Zetachain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Zetachain.

```javascript
const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Zetachain enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Zetachain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zetachain/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Zetachain RPC Method

# eth_getStorageAt - Zetachain RPC Method

Returns the value from a storage position at a given address on Zetachain. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getStorageAt` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **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 omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **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": [
    "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "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-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', '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-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

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-zetachain-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 = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
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-zetachain-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-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    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 Zetachain:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-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-zetachain-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 = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';
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 Zetachain:`);
  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/zetachain/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/zetachain/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/zetachain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Zetachain RPC Method

# eth_getTransactionByHash - Zetachain RPC Method

Returns the information about a transaction by transaction hash on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getTransactionByHash` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Zetachain
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Zetachain. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Zetachain. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zetachain/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Zetachain RPC Method

# eth_getTransactionCount - Zetachain RPC Method

Returns the number of transactions sent from an address on Zetachain, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getTransactionCount` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Zetachain
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Zetachain nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
nonce = get_transaction_count(address)
print(f'Zetachain nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Zetachain nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Zetachain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/zetachain/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zetachain/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zetachain/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Zetachain RPC Method

# eth_getTransactionReceipt - Zetachain RPC Method

Returns the receipt of a transaction by transaction hash on Zetachain. Receipt is only available for mined transactions.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_getTransactionReceipt` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Zetachain and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Zetachain. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Zetachain, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x44a31ba6329490702fae6ac42f21801b18792c422004578cc5a83723e50c8b51")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zetachain/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/zetachain/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Zetachain RPC Method

# eth_hashrate - Zetachain RPC Method

Returns the legacy `eth_hashrate` compatibility value on Zetachain. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Zetachain hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Zetachain hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Zetachain hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Zetachain hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Zetachain hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/zetachain/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/zetachain/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Zetachain RPC Method

# eth_maxPriorityFeePerGas - Zetachain RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Zetachain. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Zetachain
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Zetachain priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Zetachain priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Zetachain priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Zetachain:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Zetachain:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zetachain/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/zetachain/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zetachain/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Zetachain RPC Method

# eth_mining - Zetachain RPC Method

Checks the legacy `eth_mining` compatibility method on Zetachain. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Zetachain mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Zetachain mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Zetachain mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Zetachain mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Zetachain mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/zetachain/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/zetachain/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Zetachain RPC Method

# eth_newBlockFilter - Zetachain RPC Method

Creates a filter on Zetachain that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_newBlockFilter` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Block Monitoring** - Detect new blocks on Zetachain as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Zetachain:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zetachain/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zetachain/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Zetachain RPC Method

# eth_newFilter - Zetachain RPC Method

Creates a filter object on Zetachain based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_newFilter` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Event Monitoring** - Subscribe to specific contract events on Zetachain such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Zetachain:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zetachain/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/zetachain/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zetachain/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zetachain/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Zetachain RPC Method

# eth_newPendingTransactionFilter - Zetachain RPC Method

Creates a filter on Zetachain that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Mempool Monitoring** - Observe unconfirmed transactions on Zetachain to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Zetachain...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Zetachain:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zetachain/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zetachain/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Zetachain RPC Method

# eth_protocolVersion - Zetachain RPC Method

Returns the current Ethereum protocol version used by the Zetachain node.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_protocolVersion` is useful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Zetachain protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Zetachain protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Zetachain protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Zetachain protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zetachain protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Zetachain nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/zetachain/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/zetachain/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/zetachain/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Zetachain RPC Method

# eth_sendRawTransaction - Zetachain RPC Method

Submits a pre-signed transaction for broadcast to Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Zetachain
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Zetachain mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/zetachain/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/zetachain/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zetachain/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Zetachain RPC Method

# eth_sendTransaction - Zetachain RPC Method

Creates and sends a new transaction from an unlocked account on Zetachain. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Zetachain tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Zetachain tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Zetachain tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Zetachain tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zetachain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Zetachain dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/zetachain/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/zetachain/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Zetachain RPC Method

# eth_signTransaction - Zetachain RPC Method

Signs a transaction with the private key of the specified account on Zetachain without submitting it to the network.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Zetachain tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Zetachain tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Zetachain tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Zetachain:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/zetachain/eth_accounts) - List accounts available for signing

---

## eth_syncing - Zetachain RPC Method

# eth_syncing - Zetachain RPC Method

Returns the sync status of your Zetachain node - either `false` when fully synced, or an object describing the sync progress.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_syncing` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Zetachain node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Zetachain node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Zetachain node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/zetachain/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/zetachain/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/zetachain/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Zetachain RPC Method

# eth_uninstallFilter - Zetachain RPC Method

Removes a filter on Zetachain that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`eth_uninstallFilter` is important for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zetachain/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zetachain/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/zetachain/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zetachain/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Zetachain RPC Method

# net_listening - Zetachain RPC Method

Checks whether the connected Zetachain client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`net_listening` is useful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Zetachain node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Zetachain node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Zetachain node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/zetachain/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/zetachain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zetachain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/zetachain/web3_clientVersion) - Get node client info

---

## net_peerCount - Zetachain RPC Method

# net_peerCount - Zetachain RPC Method

Returns the number of peers currently connected to your Zetachain node.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`net_peerCount` is important for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Zetachain deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Zetachain peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Zetachain peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Zetachain peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Zetachain nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/zetachain/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/zetachain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zetachain/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/zetachain/web3_clientVersion) - Get node client info

---

## net_version - Zetachain RPC Method

# net_version - Zetachain RPC Method

Returns the current network ID on Zetachain as a decimal string. The network ID identifies which network the node is connected to.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`net_version` is essential for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Endpoint Identification** - Confirm your application is connected to the expected Zetachain network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Zetachain network ID:', networkId);

// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Zetachain network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zetachain network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/zetachain/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/zetachain/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/zetachain/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/zetachain/eth_syncing) - Check node sync progress

---

## rpc_modules - Zetachain RPC Method

# rpc_modules - Zetachain RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Zetachain endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`rpc_modules` is useful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/zetachain/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zetachain/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## txpool_content - Zetachain RPC Method

# txpool_content - Zetachain RPC Method

Returns the full pending and queued transaction pool for the connected Zetachain endpoint. Transactions are grouped first by sender address and then by nonce.

> **Non-standard method.** `txpool_content` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it because of response size and sensitivity concerns.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`txpool_content` is useful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Replacement Transaction Debugging** - Inspect multiple transactions with the same sender and nonce
- **Mempool Analytics** - Analyze which accounts dominate pending flow and how backlogs are distributed
- **Relayer Operations** - Verify whether submitted transactions are still pending, queued, or replaced
- **Fee Strategy Tuning** - Inspect real mempool fee levels and transaction types across the pending pool

## Best Practices

- Response can be very large on congested networks; be prepared to handle large payloads
- Use txpool\_status for summary statistics instead when you do not need full content
- Filter results client-side for specific addresses of interest to reduce noise
- This is a non-standard method; many shared endpoints disable this for performance reasons

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_content",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`Object, required`): Address-indexed map of processable transactions grouped by nonce
- `queued` (`Object, required`): Address-indexed map of non-processable transactions grouped by nonce

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": {
      "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7": {
        "94": {
          "from": "0x000000cd5e2aa28b0fbb66219756f36e318a4ed7",
          "to": "0xe88b4ac89a986048e48e48ff019eee4281a9791f",
          "nonce": "0x5e",
          "gas": "0x7a120",
          "gasPrice": "0x5d21dba00",
          "maxFeePerGas": "0x5d21dba00",
          "maxPriorityFeePerGas": "0x5d21dba00",
          "hash": "0xeb0eb7b61fd61739bfd87667fd787eca81d3af18bb67eaced20a7e1c0f798532",
          "value": "0x0",
          "type": "0x2"
        }
      }
    },
    "queued": {}
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_content",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_content', []);
const pendingAccounts = Object.keys(txpool.pending);
const queuedAccounts = Object.keys(txpool.queued);

console.log('Pending accounts:', pendingAccounts.length);
console.log('Queued accounts:', queuedAccounts.length);

if (pendingAccounts.length > 0) {
  const firstAccount = pendingAccounts[0];
  const firstNonce = Object.keys(txpool.pending[firstAccount])[0];
  console.log('Sample pending tx:', txpool.pending[firstAccount][firstNonce]);
}
```

```python
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_content',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
pending_accounts = list(txpool['pending'].keys())
queued_accounts = list(txpool['queued'].keys())

print('Pending accounts:', len(pending_accounts))
print('Queued accounts:', len(queued_accounts))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var txpool map[string]map[string]map[string]map[string]any
    err = client.CallContext(context.Background(), &txpool, "txpool_content")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending accounts: %d\n", len(txpool["pending"]))
    fmt.Printf("Queued accounts: %d\n", len(txpool["queued"]))
}
```

## Related Methods

- [`txpool_status`](https://www.dwellir.com/docs/zetachain/txpool_status) - Retrieve only pending and queued counters
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zetachain/eth_getTransactionByHash) - Inspect a single transaction after you identify it in the mempool
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zetachain/eth_sendRawTransaction) - Broadcast signed transactions to the network

---

## txpool_status - Zetachain RPC Method

# txpool_status - Zetachain RPC Method

Returns transaction pool counters for the connected Zetachain endpoint. The result separates transactions that are immediately processable (`pending`) from those waiting on an earlier nonce or other prerequisite (`queued`).

> **Non-standard method.** `txpool_status` is a Geth-style mempool inspection method. It is not part of the core Ethereum Execution API method set, and many shared RPC endpoints disable it.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`txpool_status` is valuable for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Mempool Monitoring** - Watch pending versus queued pressure on a node
- **Congestion Signals** - Detect bursts of transaction backlog before they show up in block-level metrics
- **Node Health Checks** - Confirm a node is accepting and classifying new transactions as expected
- **Operational Dashboards** - Surface lightweight txpool counters without pulling full transaction content

## Best Practices

- Returns pending and queued transaction counts; high pending counts suggest network congestion
- Combine with eth\_gasPrice for informed transaction submission timing decisions
- This is a non-standard method; many shared endpoints disable txpool access
- Use as a lightweight alternative to txpool\_content when you only need aggregate counts

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "txpool_status",
  "params": [],
  "id": 1
}
```

## Response Fields

- `pending` (`QUANTITY, required`): Number of processable transactions currently in the pool
- `queued` (`QUANTITY, required`): Number of transactions waiting on an earlier prerequisite such as nonce order

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "pending": "0xbaf3",
    "queued": "0x1b6"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "txpool_status",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const txpool = await provider.send('txpool_status', []);

console.log('Pending:', parseInt(txpool.pending, 16));
console.log('Queued:', parseInt(txpool.queued, 16));
```

```python
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'txpool_status',
        'params': [],
        'id': 1,
    },
)

txpool = response.json()['result']
print('Pending:', int(txpool['pending'], 16))
print('Queued:', int(txpool['queued'], 16))
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var status map[string]string
    err = client.CallContext(context.Background(), &status, "txpool_status")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %s\n", status["pending"])
    fmt.Printf("Queued: %s\n", status["queued"])
}
```

## Related Methods

- [`txpool_content`](https://www.dwellir.com/docs/zetachain/txpool_content) - Inspect the full pending and queued transaction maps
- [`eth_blockNumber`](https://www.dwellir.com/docs/zetachain/eth_blockNumber) - Track block production alongside mempool pressure
- [`eth_gasPrice`](https://www.dwellir.com/docs/zetachain/eth_gasPrice) - Compare congestion signals with fee estimates

---

## web3_clientVersion - Zetachain RPC Method

# web3_clientVersion - Zetachain RPC Method

Returns the current client software version string for your Zetachain node, including the client name, version number, OS, and runtime.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

`web3_clientVersion` is valuable for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Zetachain client:', clientVersion);

// Using fetch
const response = await fetch('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Zetachain client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zetachain client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/zetachain/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zetachain/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/zetachain/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/zetachain/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Zetachain RPC Method

# web3_sha3 - Zetachain RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/zetachain/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/zetachain/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/zetachain/web3_clientVersion) - Get node client version

---

## zkSync Era - zkEVM Layer 2 Documentation

# zkSync Era - zkEVM Layer 2 Documentation

## zkSync Era RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where zkSync Era supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on zkSync Era?

zkSync Era is the leading zero-knowledge Ethereum Virtual Machine (zkEVM), offering unparalleled scalability without compromising on security or decentralization:

### **Revolutionary Performance**

- **Instant finality** - Transactions confirmed in milliseconds
- **99% lower costs** than Ethereum mainnet
- **Zero-knowledge proofs** - Mathematical security guarantees

### **Cryptographic Security**

- **Zero-knowledge proofs** - Provably secure transactions
- **Ethereum security** - Inherits L1 security with ZK enhancements
- **Battle-tested** - Proven technology processing millions of transactions

### **Developer-First Ecosystem**

- **Full EVM compatibility** - Deploy existing contracts without changes
- **Account abstraction** - Native support for advanced wallet features
- **Growing ecosystem** - Vibrant DeFi and NFT landscape

## Quick Start with zkSync Era

Connect to zkSync Era in seconds with Dwellir's optimized endpoints:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to zkSync Era mainnet
const provider = new JsonRpcProvider(
  'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x000000000000000000000000000000000000800a');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to zkSync Era mainnet
const web3 = new Web3(
  'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to zkSync Era:', chainId === 324);

// Get gas price for optimal transaction pricing
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { zkSync } from 'viem/chains';

// Create zkSync Era client
const client = createPublicClient({
  chain: zkSync,
  transport: http('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'),
});

// Read USDC balance
const data = await client.readContract({
  address: '0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4',
  abi: contractAbi,
  functionName: 'balanceOf',
  args: ['0x000000000000000000000000000000000000800a'],
});
```

## Network Information

| Parameter    | Value      | Details          |
| ------------ | ---------- | ---------------- |
| Chain ID     | 324        | Mainnet          |
| Block Time   | < 1 second | Instant finality |
| Gas Token    | ETH        | Native token     |
| RPC Standard | Ethereum   | JSON-RPC 2.0     |

## API Reference

zkSync Era supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) with EVM compatibility. Access all standard methods with zero-knowledge proof security.

## Common Integration Patterns

### Transaction Monitoring

Monitor pending and confirmed transactions with instant finality:

```javascript
// Watch for transaction confirmation on zkSync Era
async function waitForTransaction(txHash) {
  const receipt = await provider.waitForTransaction(txHash, 1);

  // zkSync Era specific: Instant finality
  console.log('Transaction confirmed:', receipt.status === 1);
  console.log('Block number:', receipt.blockNumber);

  return receipt;
}
```

### Gas Optimization

Optimize gas costs on zkSync Era with native account abstraction:

```javascript
// Estimate gas for zkSync Era transaction
const gasEstimate = await provider.estimateGas(tx);

// Get current gas price
const gasPrice = await provider.getGasPrice();

// Calculate total cost (no L1 data fees on zkSync Era)
const totalCost = gasEstimate * gasPrice;

// zkSync Era supports paying fees with any ERC20 token
console.log('Total cost in ETH:', totalCost.toString());
```

### Event Filtering

Efficiently query contract events on zkSync Era:

```javascript
// Query events with automatic retry and pagination
async function getEvents(contract, eventName, fromBlock = 0) {
  const filter = contract.filters[eventName]();
  const events = [];
  const batchSize = 10000; // zkSync Era supports larger batch sizes

  for (let i = fromBlock; i <= currentBlock; i += batchSize) {
    const batch = await contract.queryFilter(
      filter,
      i,
      Math.min(i + batchSize - 1, currentBlock)
    );
    events.push(...batch);
  }

  return events;
}
```

## Performance Best Practices

### 1. **Batch Requests**

Combine multiple RPC calls for optimal performance:

```javascript
const batch = [
  { method: 'eth_blockNumber', params: [] },
  { method: 'eth_gasPrice', params: [] },
  { method: 'eth_getBalance', params: [address, 'latest'] }
];

const results = await provider.send(batch);
```

### 2. **Connection Pooling**

Reuse provider instances to minimize connection overhead:

```javascript
// Singleton pattern for provider
class ZkSyncProvider {
  static instance = null;

  static getInstance() {
    if (!this.instance) {
      this.instance = new JsonRpcProvider(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'
      );
    }
    return this.instance;
  }
}
```

### 3. **Smart Caching**

Cache immutable data to reduce API calls:

```javascript
const cache = new Map();

async function getCachedBlockData(blockNumber) {
  const key = `block_${blockNumber}`;

  if (!cache.has(key)) {
    const block = await provider.getBlock(blockNumber);
    cache.set(key, block);
  }

  return cache.get(key);
}
```

## Troubleshooting Common Issues

### Error: "Insufficient funds"

zkSync Era transactions require ETH for gas fees, but also support ERC20 fee payments:

```javascript
// Check ETH balance for gas fees
const balance = await provider.getBalance(address);
const gasEstimate = await provider.estimateGas(tx);
const gasPrice = await provider.getGasPrice();
const totalRequired = gasEstimate * gasPrice + tx.value;

if (balance < totalRequired) {
  console.log(`Need ${totalRequired - balance} more ETH`);
  // Alternative: Use paymaster for ERC20 fee payment
}
```

### Error: "Transaction underpriced"

zkSync Era uses dynamic gas pricing. Always use current fee data:

```javascript
// Get current fee data
const feeData = await provider.getFeeData();

const tx = {
  to: recipient,
  value: amount,
  maxFeePerGas: feeData.maxFeePerGas,
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
  gasLimit: 21000n,
  type: 2 // EIP-1559 transaction
};
```

### Error: "Rate limit exceeded"

Implement exponential backoff for resilient applications:

```javascript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving from L1 to zkSync Era requires minimal changes:

```javascript
// Before (Ethereum)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (zkSync Era)
const provider = new JsonRpcProvider(
  'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'
);

// Smart contracts work identically (EVM compatible)
// Same tooling and libraries
// Account abstraction support
// Note: Different chain ID (324)
// Note: Separate block numbers
// Note: Zero-knowledge proof finality
```

## Smoke Tests

Verify your zkSync Era integration with these quick tests:

```javascript
// Test 1: Verify chain connection
const chainId = await provider.send('eth_chainId', []);
console.assert(parseInt(chainId, 16) === 324, 'Connected to zkSync Era');

// Test 2: Check latest block
const blockNumber = await provider.send('eth_blockNumber', []);
console.log('Latest block:', parseInt(blockNumber, 16));

// Test 3: Query a known contract (USDC)
const usdcBalance = await provider.send('eth_call', [{
  to: '0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4',
  data: '0x70a08231000000000000000000000000000000000000000000000000000000000000800a'
}, 'latest']);
console.log('USDC balance call successful:', usdcBalance);
```

## Resources & Tools

### Official Resources

- [zkSync Documentation](https://docs.zksync.io/)
- [zkSync Era Bridge](https://bridge.zksync.io/)
- [zkSync Block Explorer](https://explorer.zksync.io/)

### Developer Tools

- [Hardhat Config](https://docs.zksync.io/build/tooling/hardhat)
- [Foundry Setup](https://docs.zksync.io/zksync-era/tooling/foundry/overview)
- [Atlas IDE](https://app.atlaszk.com/)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building on zkSync Era with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - zkSync RPC Method

# debug_traceBlock - zkSync RPC Method

Traces all transactions in a block on zkSync Era by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for zkSync Era - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on zkSync
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on zkSync:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in zkSync blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zksync-era/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zksync-era/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - zkSync RPC Method

# debug_traceBlockByHash - zkSync RPC Method

Traces all transactions in a block on zkSync Era identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for zkSync Era - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on zkSync
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on zkSync:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on zkSync:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

zkSync |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32002 | Resource unavailable | Node is syncing or the requested block is not yet available |

```javascript
async function safeTraceBlockByHash(provider, blockHash, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByHash', [blockHash, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByHash not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockHash} not found - verify the hash is correct`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByHash', [
        blockHash,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/zksync-era/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zksync-era/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zksync-era/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - zkSync RPC Method

# debug_traceBlockByNumber - zkSync RPC Method

Traces all transactions in a block on zkSync Era identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for zkSync Era - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of zkSync execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on zkSync:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on zkSync:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

zkSync - it may be in the future |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32602 | Invalid params | Check that the block number is a valid hex string or tag |

```javascript
async function safeTraceBlockByNumber(provider, blockNumber, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByNumber', [blockNumber, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByNumber not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockNumber} not found on zkSync`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByNumber', [
        blockNumber,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/zksync-era/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zksync-era/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zksync-era/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - zkSync RPC Method

# debug_traceCall - zkSync RPC Method

Traces a call on zkSync Era without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for zkSync Era - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on zkSync
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "data": "0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
        "data": "0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
        "data": "0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    data: '0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    data: '0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    'data': '0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
        "data": "0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on zkSync to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on zkSync:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on zkSync:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/zksync-era/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zksync-era/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - zkSync RPC Method

# debug_traceTransaction - zkSync RPC Method

Traces a transaction execution on zkSync Era by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on zkSync
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/zksync-era/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zksync-era/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - zkSync RPC Method

# eth_accounts - zkSync RPC Method

Returns a list of addresses owned by the client on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/zksync-era/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - zkSync RPC Method

# eth_blockNumber - zkSync RPC Method

Returns the number of the most recent block on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_blockNumber` is fundamental for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Syncing Applications** - Keep your dApp in sync with the latest zkSync blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('zkSync block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('zkSync block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'zkSync block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'zkSync block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("zkSync block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on zkSync:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on zkSync:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your zkSync node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/zksync-era/eth_syncing) - Check if node is still syncing

---

## eth_call - zkSync RPC Method

# eth_call - zkSync RPC Method

Executes a new message call immediately without creating a transaction on zkSync Era. Used for reading smart contract state.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

The `eth_call` method serves these key scenarios for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on zkSync
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';
const walletAddress = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on zkSync. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on zkSync
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on zkSync Era

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "data": "0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "data": "0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    data := common.FromHex("0x70a082310000000000000000000000005AEa5775959fBC2557Cc8789bC1bf90A239D9a91")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - zkSync RPC Method

# eth_chainId - zkSync RPC Method

Returns the chain ID used for transaction signing on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_chainId` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/zksync-era/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/zksync-era/eth_syncing) - Check sync status

---

## eth_coinbase - zkSync RPC Method

# eth_coinbase - zkSync RPC Method

Checks the legacy `eth_coinbase` compatibility method on zkSync Era. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('zkSync coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('zkSync coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'zkSync coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'zkSync coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("zkSync coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of zkSync nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/zksync-era/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/zksync-era/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/zksync-era/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - zkSync RPC Method

# eth_estimateGas - zkSync RPC Method

Estimates the gas necessary to execute a transaction on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on zkSync
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on zkSync.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like zkSync may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "to": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zksync-era/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Send transaction

---

## eth_feeHistory - zkSync RPC Method

# eth_feeHistory - zkSync RPC Method

Returns historical gas fee data on zkSync Era, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on zkSync without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on zkSync.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on zkSync) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zksync-era/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/zksync-era/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - zkSync RPC Method

# eth_gasPrice - zkSync RPC Method

Returns the current gas price on zkSync Era in wei.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on zkSync
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of zkSync. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on zkSync, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on zkSync: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if zkSync supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/zksync-era/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/zksync-era/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - zkSync RPC Method

# eth_getBalance - zkSync RPC Method

Returns the balance of a given address on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getBalance` is fundamental for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Wallet applications**: Display user balances and enable balance-dependent operations on zkSync
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to zkSync Era
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on zkSync Era. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} zkSync`);
  return balance;
}

displayBalance('0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on zkSync at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 zkSync')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 zkSync')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on zkSync Era.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/zksync-era/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - zkSync RPC Method

# eth_getBlockByHash - zkSync RPC Method

Returns information about a block by hash on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getBlockByHash` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on zkSync Era
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on zkSync Era.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on zkSync Era.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/zksync-era/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - zkSync RPC Method

# eth_getBlockByNumber - zkSync RPC Method

Returns information about a block by block number on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getBlockByNumber` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on zkSync Era
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on zkSync Era with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on zkSync Era. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/zksync-era/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - zkSync RPC Method

# eth_getBlockReceipts - zkSync RPC Method

Returns all transaction receipts for a block on zkSync Era. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getBlockReceipts` is useful for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for zkSync Era, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on zkSync Era. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x896c63ec4c3bcacb3367166437ae2b90530df268c3e7b870fb9138f98b0b060c",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - zkSync RPC Method

# eth_getCode - zkSync RPC Method

Returns the bytecode at a given address on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getCode` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on zkSync
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on zkSync:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on zkSync:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/zksync-era/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/zksync-era/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - zkSync RPC Method

# eth_getFilterChanges - zkSync RPC Method

Polls a filter on zkSync Era for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getFilterChanges` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on zkSync
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on zkSync:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zksync-era/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zksync-era/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zksync-era/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zksync-era/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/zksync-era/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - zkSync RPC Method

# eth_getFilterLogs - zkSync RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on zkSync Era. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getFilterLogs` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on zkSync
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zksync-era/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/zksync-era/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zksync-era/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - zkSync RPC Method

# eth_getLogs - zkSync RPC Method

Returns an array of all logs matching a given filter object on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on zkSync for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on zkSync Era
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on zkSync.

```javascript
const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if zkSync enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on zkSync Era, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zksync-era/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - zkSync RPC Method

# eth_getStorageAt - zkSync RPC Method

Returns the value from a storage position at a given address on zkSync Era. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getStorageAt` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **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 RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **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": [
    "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "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-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', '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-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';

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-zksync-era-mainnet-full.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 = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
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-zksync-era-mainnet-full.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-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    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 zkSync:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.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-zksync-era-mainnet-full.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 = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';
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 zkSync:`);
  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/zksync-era/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/zksync-era/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/zksync-era/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - zkSync RPC Method

# eth_getTransactionByHash - zkSync RPC Method

Returns the information about a transaction by transaction hash on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getTransactionByHash` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on zkSync Era
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on zkSync Era. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on zkSync Era. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - zkSync RPC Method

# eth_getTransactionCount - zkSync RPC Method

Returns the number of transactions sent from an address on zkSync Era, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getTransactionCount` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on zkSync
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('zkSync nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
nonce = get_transaction_count(address)
print(f'zkSync nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("zkSync nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on zkSync:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/zksync-era/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - zkSync RPC Method

# eth_getTransactionReceipt - zkSync RPC Method

Returns the receipt of a transaction by transaction hash on zkSync Era. Receipt is only available for mined transactions.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getTransactionReceipt` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on zkSync Era and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on zkSync Era. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on zkSync Era, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const txHash = '0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0xc4c7231ab3f1d8feaaf4e2b9933696e37095d0af84cb6cc70f48493b38f3a731")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/zksync-era/eth_getLogs) - Query logs by filter

---

## eth_hashrate - zkSync RPC Method

# eth_hashrate - zkSync RPC Method

Returns the legacy `eth_hashrate` compatibility value on zkSync Era. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('zkSync hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('zkSync hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'zkSync hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'zkSync hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("zkSync hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/zksync-era/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/zksync-era/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/zksync-era/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - zkSync RPC Method

# eth_maxPriorityFeePerGas - zkSync RPC Method

Returns the current suggested priority fee (tip) per gas in wei on zkSync Era. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on zkSync
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('zkSync priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'zkSync priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("zkSync priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on zkSync:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on zkSync:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zksync-era/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/zksync-era/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - zkSync RPC Method

# eth_mining - zkSync RPC Method

Checks the legacy `eth_mining` compatibility method on zkSync Era. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('zkSync mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('zkSync mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'zkSync mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'zkSync mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("zkSync mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/zksync-era/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/zksync-era/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/zksync-era/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - zkSync RPC Method

# eth_newBlockFilter - zkSync RPC Method

Creates a filter on zkSync Era that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_newBlockFilter` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Block Monitoring** - Detect new blocks on zkSync as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on zkSync:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zksync-era/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/zksync-era/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zksync-era/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - zkSync RPC Method

# eth_newFilter - zkSync RPC Method

Creates a filter object on zkSync Era based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_newFilter` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Event Monitoring** - Subscribe to specific contract events on zkSync such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on zkSync:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zksync-era/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/zksync-era/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zksync-era/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zksync-era/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - zkSync RPC Method

# eth_newPendingTransactionFilter - zkSync RPC Method

Creates a filter on zkSync Era that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Mempool Monitoring** - Observe unconfirmed transactions on zkSync to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for RWA tokenization ($1.9B, 25% market share), hyperchain deployment via ZK Stack, and cross-chain DeFi

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on zkSync...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on zkSync:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zksync-era/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - zkSync RPC Method

# eth_protocolVersion - zkSync RPC Method

Returns the current Ethereum protocol version used by the zkSync Era node.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_protocolVersion` is useful for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('zkSync protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('zkSync protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'zkSync protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
print(f'zkSync protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("zkSync protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of zkSync nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/zksync-era/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/zksync-era/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/zksync-era/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - zkSync RPC Method

# eth_sendRawTransaction - zkSync RPC Method

Submits a pre-signed transaction for broadcast to zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to zkSync
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the zkSync mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/zksync-era/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/zksync-era/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zksync-era/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - zkSync RPC Method

# eth_sendTransaction - zkSync RPC Method

Creates and sends a new transaction from an unlocked account on zkSync Era. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('zkSync tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('zkSync tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'zkSync tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'zkSync tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("zkSync tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on zkSync dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/zksync-era/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/zksync-era/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - zkSync RPC Method

# eth_signTransaction - zkSync RPC Method

Signs a transaction with the private key of the specified account on zkSync Era without submitting it to the network.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed zkSync tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed zkSync tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed zkSync tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on zkSync:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/zksync-era/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/zksync-era/eth_accounts) - List accounts available for signing

---

## eth_syncing - zkSync RPC Method

# eth_syncing - zkSync RPC Method

Returns the sync status of your zkSync Era node - either `false` when fully synced, or an object describing the sync progress.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_syncing` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('zkSync node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('zkSync node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("zkSync node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/zksync-era/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/zksync-era/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/zksync-era/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/zksync-era/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - zkSync RPC Method

# eth_uninstallFilter - zkSync RPC Method

Removes a filter on zkSync Era that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_uninstallFilter` is important for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zksync-era/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zksync-era/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/zksync-era/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zksync-era/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - zkSync RPC Method

# net_listening - zkSync RPC Method

Checks whether the connected zkSync Era client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`net_listening` is useful for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('zkSync node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'zkSync node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("zkSync node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/zksync-era/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/zksync-era/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zksync-era/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/zksync-era/web3_clientVersion) - Get node client info

---

## net_peerCount - zkSync RPC Method

# net_peerCount - zkSync RPC Method

Returns the number of peers currently connected to your zkSync Era node.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`net_peerCount` is important for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific zkSync deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`zkSync peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'zkSync peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("zkSync peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of zkSync nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/zksync-era/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/zksync-era/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zksync-era/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/zksync-era/web3_clientVersion) - Get node client info

---

## net_version - zkSync RPC Method

# net_version - zkSync RPC Method

Returns the current network ID on zkSync Era as a decimal string. The network ID identifies which network the node is connected to.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`net_version` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Endpoint Identification** - Confirm your application is connected to the expected zkSync network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('zkSync network ID:', networkId);

// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'zkSync network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("zkSync network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/zksync-era/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/zksync-era/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/zksync-era/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/zksync-era/eth_syncing) - Check node sync progress

---

## web3_clientVersion - zkSync RPC Method

# web3_clientVersion - zkSync RPC Method

Returns the current client software version string for your zkSync Era node, including the client name, version number, OS, and runtime.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`web3_clientVersion` is valuable for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('zkSync client:', clientVersion);

// Using fetch
const response = await fetch('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'zkSync client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("zkSync client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/zksync-era/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zksync-era/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/zksync-era/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/zksync-era/net_peerCount) - Get number of connected peers

---

## web3_sha3 - zkSync RPC Method

# web3_sha3 - zkSync RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on zkSync Era.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/zksync-era/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/zksync-era/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/zksync-era/web3_clientVersion) - Get node client version

---

## Zora - Creator Economy & NFT L2 Documentation

# Zora - Creator Economy & NFT L2 Documentation

## Zora RPC plans and rate limits

- **Free plan:** 20 responses per second, up to 100,000 responses a day.
- **Plans:** $49/mo, $299/mo, $999/mo with 25M, 150M, and 500M included responses. Overages billed at $5/$3/$2 per million responses respectively.
- **Paid rate limits:** 100 to 5,000 responses per second (bursts from 500 to 10,000), no daily limit.
- **Billing:** 1 response = 1 API credit on every shared plan, over HTTPS or WebSocket (WSS) where Zora supports it.

Details: [Pricing](https://www.dwellir.com/docs/getting-started/pricing) · [Rate limits](https://www.dwellir.com/docs/getting-started/rate-limits) · [Authentication](https://www.dwellir.com/docs/getting-started/authentication) · [Archive nodes](https://www.dwellir.com/docs/getting-started/archive-nodes)

## Why Build on Zora?

Zora is the leading Ethereum Layer 2 optimized for creators, NFTs, and onchain media. Built on Optimism's OP Stack, Zora offers the perfect infrastructure for the creator economy:

### **Creator-First Design**

- **0.000777 ETH mint rewards** - Get rewarded for onchain activity
- **Gas-optimized NFT operations** - Efficient minting, trading, and transfers
- **Built-in creator tools** - Native support for royalties and revenue sharing

### **Lightning Fast & Affordable**

- **2-second block times** - Near-instant NFT transactions
- **Ultra-low fees** - Mint NFTs for pennies, not dollars
- **EIP-4844 enabled** - Leveraging blob data for maximum cost efficiency

### **Battle-Tested Infrastructure**

- **OP Stack security** - Inherits Ethereum's security guarantees
- **7777777 Chain ID** - Lucky sevens for the creator economy
- **Ethereum compatibility** - Use existing tools and wallets

### **Thriving NFT Ecosystem**

- **Zora Protocol integration** - Native NFT marketplace functionality
- **Creator rewards system** - Earn from every mint and interaction
- **Major creator adoptions** - Home to top artists and projects

## Quick Start with Zora

Connect to Zora's creator-optimized infrastructure in seconds:

### Installation & Setup

Ethers.js v6
Web3.js
Viem

```javascript
import { JsonRpcProvider } from 'ethers';

// Connect to Zora mainnet
const provider = new JsonRpcProvider(
  'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get the latest block
const block = await provider.getBlock('latest');
console.log('Latest block:', block.number);

// Query account balance
const balance = await provider.getBalance('0x...');
console.log('Balance:', balance.toString());
```

```javascript
const Web3 = require('web3');

// Connect to Zora mainnet
const web3 = new Web3(
  'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Get chain ID to verify connection
const chainId = await web3.eth.getChainId();
console.log('Connected to Zora:', chainId === 7777777);

// Get gas price for optimal NFT transactions
const gasPrice = await web3.eth.getGasPrice();
console.log('Current gas price:', gasPrice);
```

```typescript
import { createPublicClient, http } from 'viem';
import { zora } from 'viem/chains';

// Create Zora client
const client = createPublicClient({
  chain: zora,
  transport: http('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'),
});

// Read NFT contract data
const data = await client.readContract({
  address: '0x...',
  abi: erc721Abi,
  functionName: 'tokenURI',
  args: [1],
});
```

## Network Information

| Parameter    | Value     | Details      |
| ------------ | --------- | ------------ |
| Chain ID     | 7777777   | Mainnet      |
| Block Time   | 2 seconds | Average      |
| Gas Token    | ETH       | Native token |
| RPC Standard | Ethereum  | JSON-RPC 2.0 |

## API Reference

Zora supports the full [Ethereum JSON-RPC API specification](https://ethereum.org/developers/docs/apis/json-rpc/) plus OP Stack L2 optimizations for creator applications.

## Creator-Focused Integration Patterns

### NFT Minting & Management

Efficiently mint and manage NFTs on Zora:

```javascript
// Mint NFT with creator rewards
async function mintNFTWithRewards(contract, to, tokenURI) {
  const tx = {
    to: contract.address,
    data: contract.interface.encodeFunctionData('mint', [to, tokenURI]),
    // Zora rewards: 0.000777 ETH per mint
    value: parseEther('0.000777')
  };

  const receipt = await provider.sendTransaction(tx);

  // Check for creator reward distribution
  const rewardEvents = receipt.logs.filter(log =>
    log.topics[0] === creatorRewardEventSignature
  );

  return { receipt, rewards: rewardEvents };
}
```

### Real-time NFT Tracking

Monitor NFT transfers and marketplace activity:

```javascript
// Watch for NFT transfers in real-time
const nftFilter = {
  address: contractAddress,
  topics: [
    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // Transfer
    null, // from (any)
    null  // to (any)
  ]
};

provider.on(nftFilter, (log) => {
  const transfer = parseLog(log);
  console.log(`NFT ${transfer.tokenId} transferred from ${transfer.from} to ${transfer.to}`);
});
```

### Creator Revenue Optimization

Track and optimize creator earnings:

```javascript
// Calculate total creator rewards
async function getCreatorEarnings(creatorAddress, fromBlock = 0) {
  const rewardFilter = {
    address: ZORA_REWARDS_CONTRACT,
    topics: [
      '0x...', // RewardPaid event signature
      ethers.utils.hexZeroPad(creatorAddress, 32)
    ]
  };

  const logs = await provider.getLogs({
    ...rewardFilter,
    fromBlock,
    toBlock: 'latest'
  });

  const totalRewards = logs.reduce((sum, log) => {
    const reward = parseLog(log);
    return sum.add(reward.amount);
  }, BigNumber.from(0));

  return totalRewards;
}
```

### Advanced NFT Querying

Query NFT metadata and ownership efficiently:

```javascript
// Batch query NFT metadata
async function getNFTBatch(contractAddress, tokenIds) {
  const contract = new Contract(contractAddress, erc721Abi, provider);
  const batchSize = 50; // Zora recommended batch size

  const results = [];
  for (let i = 0; i < tokenIds.length; i += batchSize) {
    const batch = tokenIds.slice(i, i + batchSize);

    const promises = batch.map(async (tokenId) => ({
      tokenId,
      owner: await contract.ownerOf(tokenId),
      tokenURI: await contract.tokenURI(tokenId),
    }));

    const batchResults = await Promise.all(promises);
    results.push(...batchResults);
  }

  return results;
}
```

## Performance Best Practices for Creators

### 1. **Optimize NFT Operations**

Use efficient patterns for high-volume NFT operations:

```javascript
// Batch mint for gas efficiency
async function batchMintNFTs(contract, recipients, tokenURIs) {
  const batchData = recipients.map((to, i) =>
    contract.interface.encodeFunctionData('mint', [to, tokenURIs[i]])
  );

  const multicallData = contract.interface.encodeFunctionData('multicall', [batchData]);

  return await contract.multicall(batchData, {
    value: parseEther((0.000777 * recipients.length).toString())
  });
}
```

### 2. **Smart Caching for Metadata**

Cache NFT metadata to improve user experience:

```javascript
const metadataCache = new Map();

async function getCachedMetadata(tokenURI) {
  if (!metadataCache.has(tokenURI)) {
    const response = await fetch(tokenURI);
    const metadata = await response.json();
    metadataCache.set(tokenURI, metadata);
  }

  return metadataCache.get(tokenURI);
}
```

### 3. **Event-Driven Architecture**

Build responsive creator tools with event listeners:

```javascript
// Listen for all creator-relevant events
const eventFilters = [
  { topics: [transferEventSignature] }, // NFT transfers
  { topics: [mintEventSignature] },     // New mints
  { topics: [saleEventSignature] },     // Marketplace sales
  { topics: [rewardEventSignature] }    // Creator rewards
];

eventFilters.forEach(filter => {
  provider.on(filter, handleCreatorEvent);
});

function handleCreatorEvent(log) {
  const eventType = identifyEventType(log);

  switch(eventType) {
    case 'TRANSFER':
      updateOwnershipRecords(log);
      break;
    case 'MINT':
      trackNewCreation(log);
      break;
    case 'SALE':
      updateCreatorEarnings(log);
      break;
    case 'REWARD':
      distributeMintRewards(log);
      break;
  }
}
```

## Troubleshooting Creator Applications

### Error: "Insufficient mint reward"

Zora requires 0.000777 ETH for creator rewards on mints:

```javascript
// Always include mint reward in NFT transactions
const mintTx = {
  to: nftContract.address,
  data: mintData,
  value: parseEther('0.000777'), // Required for Zora rewards
  gasLimit: 100000n
};
```

### Error: "Token does not exist"

Handle NFT queries gracefully for better UX:

```javascript
async function safeGetTokenURI(contract, tokenId) {
  try {
    return await contract.tokenURI(tokenId);
  } catch (error) {
    if (error.reason === 'ERC721: invalid token ID') {
      return null; // Token doesn't exist yet
    }
    throw error; // Re-throw other errors
  }
}
```

### Error: "Rate limit exceeded"

Implement retry logic for high-volume creator applications:

```javascript
async function mintWithRetry(contract, params, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await contract.mint(...params);
    } catch (error) {
      if (error.code === 429 && i < maxRetries - 1) {
        const delay = Math.min(2 ** i * 1000, 10000); // Cap at 10s
        await new Promise(r => setTimeout(r, delay));
      } else {
        throw error;
      }
    }
  }
}
```

## Migration Guide

### From Ethereum Mainnet

Moving NFT projects from L1 to Zora L2:

```javascript
// Before (Ethereum L1)
const provider = new JsonRpcProvider('https://eth-rpc.example.com');

// After (Zora L2)
const provider = new JsonRpcProvider(
  'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'
);

// Same NFT standards (ERC-721, ERC-1155)
// Same tooling and libraries work
// Dramatically lower fees
// Note: Different chain ID (7777777)
// Note: Creator rewards system (0.000777 ETH)
// Note: L1 data fees apply
```

### From Polygon

Zora offers better creator economics than Polygon:

```javascript
// Enhanced creator benefits on Zora:
// - Built-in mint rewards (0.000777 ETH per mint)
// - Lower gas fees than Polygon
// - Native creator tools and royalty enforcement
// - Better Ethereum ecosystem integration
```

## Creator Tools & Resources

### Official Resources

- [Zora Documentation](https://docs.zora.co)
- [Zora Explorer](https://explorer.zora.energy)

### Creator Tools

- [Zora Create](https://zora.co/create) - Easy NFT minting
- [Creator Toolkit](https://github.com/ourzora/zora-protocol) - Smart contract templates

### Developer Resources

- [Zora Documentation](https://docs.zora.co)

### Need Help?

- **Email**: <support@dwellir.com>
- **Docs**: You're here!
- **Dashboard**: [dashboard.dwellir.com](https://dashboard.dwellir.com)

***

*Start building the future of the creator economy on Zora with Dwellir's enterprise-grade RPC infrastructure. [Get your API key](https://dashboard.dwellir.com/register)*

---

## debug_traceBlock - Zora RPC Method

# debug_traceBlock - Zora RPC Method

Traces all transactions in a block on Zora by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Zora - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlock` is valuable for NFT creators, digital artists, brands, and onchain media builders:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Zora
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `calls` (`Array, required`): Sub-calls made during execution

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
        "message": "invalid block payload"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlock', [
    block_rlp,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type TraceResult struct {
    TxHash string      `json:"txHash"`
    Result CallTrace   `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlock",
        "params":  []interface{}{blockRlp, map[string]string{"tracer": "callTracer"}},
        "id":      1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY", "application/json", bytes.NewReader(body))
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Zora:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Zora blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zora/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zora/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zora/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zora/debug_traceCall) - Trace a call without creating a transaction

---

## debug_traceBlockByHash - Zora RPC Method

# debug_traceBlockByHash - Zora RPC Method

Traces all transactions in a block on Zora identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Zora - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on Zora
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on Zora:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on Zora:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

Zora |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32002 | Resource unavailable | Node is syncing or the requested block is not yet available |

```javascript
async function safeTraceBlockByHash(provider, blockHash, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByHash', [blockHash, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByHash not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockHash} not found - verify the hash is correct`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByHash', [
        blockHash,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/zora/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zora/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zora/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zora/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zora/eth_getBlockByHash) - Get block details by hash (without traces)

---

## debug_traceBlockByNumber - Zora RPC Method

# debug_traceBlockByNumber - Zora RPC Method

Traces all transactions in a block on Zora identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or `"latest"` to get full execution traces of every transaction in that block.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for Zora - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByNumber` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Historical Block Analysis** - Trace transactions in any past block by number, enabling time-series analysis of Zora execution patterns
- **Gas Consumption Patterns** - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Debugging State Transitions** - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
- **Automated Block Scanning** - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

## Best Practices

- Requires archive node access; not available on standard full nodes
- Use the callTracer for faster execution when full opcode detail is not needed
- A full trace of a dense block can be hundreds of megabytes in size
- Paginate results and process traces in batches for large blocks

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block #999999999 not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace latest block with call tracer
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block with prestate tracer
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace latest block with call tracer
const callTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Latest block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  const gasUsed = parseInt(trace.result.gasUsed, 16);
  const status = trace.result.error ? 'REVERTED' : 'OK';
  console.log(`  ${trace.txHash}: ${gasUsed} gas [${status}]`);

  // Print sub-calls
  if (trace.result.calls) {
    for (const call of trace.result.calls) {
      console.log(`    -> ${call.type} to ${call.to}`);
    }
  }
}

// Trace a specific historical block
const blockNum = '0xF4240'; // block 1,000,000
const historicalTraces = await provider.send('debug_traceBlockByNumber', [
  blockNum,
  { tracer: 'callTracer' }
]);
console.log(`Block 1000000 had ${historicalTraces.length} transactions`);

// Trace with prestate tracer for state analysis
const prestateTraces = await provider.send('debug_traceBlockByNumber', [
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_number(block_number, tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_number, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace latest block
traces = trace_block_by_number('latest')
print(f'Latest block: {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    has_error = 'error' in result
    print(f'  {trace["txHash"]}: {gas_used} gas {"[REVERTED]" if has_error else ""}')

# Trace specific block
traces = trace_block_by_number('0xF4240')
print(f'Block 1000000: {len(traces)} transactions')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_number = w3.eth.block_number
traces = w3.provider.make_request('debug_traceBlockByNumber', [
    hex(block_number),
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions in block {block_number}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace struct {
    Type    string      `json:"type"`
    From    string      `json:"from"`
    To      string      `json:"to"`
    Value   string      `json:"value"`
    Gas     string      `json:"gas"`
    GasUsed string      `json:"gasUsed"`
    Input   string      `json:"input"`
    Output  string      `json:"output"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func traceBlockByNumber(blockNumber string) ([]TraceResult, error) {
    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByNumber",
        "params": []interface{}{
            blockNumber,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    if err := json.Unmarshal(data, &response); err != nil {
        return nil, err
    }

    return response.Result, nil
}

func main() {
    traces, err := traceBlockByNumber("latest")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Latest block: %d transactions\n", len(traces))
    for _, trace := range traces {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED"
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Zora:

```javascript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}
```

### 2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Zora:

```python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls
```

### 3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

```javascript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}
```

Zora - it may be in the future |
\| -32000 | Missing trie node | Node is not an archive node or state has been pruned - use an archive endpoint |
\| -32601 | Method not found | Debug namespace is not enabled on the node |
\| -32603 | Internal error | Block may be too large to trace - increase timeout or use `disableStorage` |
\| -32005 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
\| -32602 | Invalid params | Check that the block number is a valid hex string or tag |

```javascript
async function safeTraceBlockByNumber(provider, blockNumber, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByNumber', [blockNumber, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByNumber not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockNumber} not found on Zora`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByNumber', [
        blockNumber,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/zora/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zora/debug_traceBlockByHash) - Trace all transactions in a block by hash
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zora/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/zora/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Get block details by number (without traces)

---

## debug_traceCall - Zora RPC Method

# debug_traceCall - Zora RPC Method

Traces a call on Zora without creating a transaction on-chain. This is a dry-run trace - it executes the call in the EVM at a specified block and returns detailed execution traces including opcodes, internal calls, and state changes, without any on-chain side effects.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

This method requires an archive node with debug APIs enabled when tracing against historical blocks. For `"latest"` or `"pending"` blocks, a full node with debug APIs may suffice. Dwellir provides archive node access for Zora - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceCall` is powerful for NFT creators, digital artists, brands, and onchain media builders:

- **Simulating Transactions Before Sending** - Preview the full execution trace of a transaction before committing it on-chain, catching reverts and unexpected behavior before spending gas on Zora
- **Debugging Contract Interactions** - Step through contract execution at the opcode level to understand complex interactions, delegate calls, and proxy patterns for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Gas Estimation With Trace Details** - Go beyond `eth_estimateGas` by seeing exactly which opcodes and internal calls consume gas, enabling targeted optimization
- **Security Analysis** - Analyze how a contract would execute a specific call, detecting reentrancy, unexpected state modifications, and access control issues

## Best Practices

- Requires archive node access when tracing against historical blocks
- Use the stateDiff tracer for storage change analysis on simulated calls
- The prestateTracer shows account state before the call executes
- The callTracer is fastest for understanding call structure

## Request Parameters

- `callObject` (`Object, required`): Transaction call object (same format as eth_call)
- `blockNumber` (`QUANTITY|TAG, required`): Block number as hex string, or tag: "earliest", "latest", "pending"
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)
- `from` (`DATA, optional`): Sender address (defaults to zero address)
- `to` (`DATA, required`): Recipient / contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `maxFeePerGas` (`QUANTITY, optional`): Max fee per gas (EIP-1559)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Max priority fee per gas (EIP-1559)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Encoded function call data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceCall",
  "params": [
    {
      "from": "0x1234567890abcdef1234567890abcdef12345678",
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `structLogs[].stack` (`Array<DATA>, required`): Stack contents (if not disabled)
- `structLogs[].storage` (`Object, required`): Storage changes (if not disabled)
- `address` (`Object, required`): State of each account touched by the call
- `address.balance` (`QUANTITY, required`): Account balance
- `address.nonce` (`QUANTITY, required`): Account nonce
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots accessed

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x5e1a",
    "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0xfedcba0987654321fedcba0987654321fedcba09",
        "gas": "0x2fa4060",
        "gasUsed": "0x2510",
        "input": "0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
      }
    ]
  }
}
```

## Error Responses

### Error Response (Reverted Call)

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "value": "0x0",
    "gas": "0x2faf080",
    "gasUsed": "0x831b",
    "input": "0xa9059cbb...",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020...",
    "error": "execution reverted",
    "revertReason": "ERC20: transfer amount exceeds balance"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace a read-only contract call with call tracer
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with default opcode tracer
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceCall",
    "params": [
      {
        "to": "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
      },
      "latest",
      {"disableStorage": true, "enableReturnData": true}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Trace a simple read-only contract call
const callTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'callTracer' }
]);

console.log(`Call type: ${callTrace.type}`);
console.log(`Gas used: ${parseInt(callTrace.gasUsed, 16)}`);
console.log(`Sub-calls: ${(callTrace.calls || []).length}`);

if (callTrace.error) {
  console.log(`Error: ${callTrace.error}`);
  console.log(`Revert reason: ${callTrace.revertReason}`);
} else {
  console.log(`Output: ${callTrace.output}`);
}

// Trace with prestate tracer to see state access
const prestateTrace = await provider.send('debug_traceCall', [
  {
    to: '0x4200000000000000000000000000000000000006',
    data: '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
  },
  'latest',
  { tracer: 'prestateTracer' }
]);

for (const [addr, state] of Object.entries(prestateTrace)) {
  console.log(`Account ${addr}:`);
  if (state.balance) console.log(`  Balance: ${state.balance}`);
  if (state.storage) console.log(`  Storage slots: ${Object.keys(state.storage).length}`);
}
```

```python
import requests

def trace_call(call_object, block='latest', tracer='callTracer', **kwargs):
    tracer_config = {'tracer': tracer, **kwargs}
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceCall',
            'params': [call_object, block, tracer_config],
            'id': 1
        }
    )
    result = response.json()
    if 'error' in result:
        raise Exception(f'RPC error: {result["error"]["message"]}')
    return result['result']

# Trace a read-only contract call
call_obj = {
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x70a082310000000000000000000000004200000000000000000000000000000000000006'
}

trace = trace_call(call_obj)
gas_used = int(trace['gasUsed'], 16)
print(f'Call type: {trace["type"]}')
print(f'Gas used: {gas_used}')

if 'error' in trace:
    print(f'Error: {trace["error"]}')
else:
    print(f'Output: {trace["output"]}')

# Show sub-calls
for call in trace.get('calls', []):
    print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

trace = w3.provider.make_request('debug_traceCall', [
    call_obj,
    'latest',
    {'tracer': 'callTracer'}
])
print(f'Result: {trace["result"]["type"]}')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type CallTrace struct {
    Type         string      `json:"type"`
    From         string      `json:"from"`
    To           string      `json:"to"`
    Value        string      `json:"value"`
    Gas          string      `json:"gas"`
    GasUsed      string      `json:"gasUsed"`
    Input        string      `json:"input"`
    Output       string      `json:"output"`
    Error        string      `json:"error,omitempty"`
    RevertReason string      `json:"revertReason,omitempty"`
    Calls        []CallTrace `json:"calls,omitempty"`
}

func main() {
    callObj := map[string]string{
        "to":   "0x4200000000000000000000000000000000000006",
        "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006",
    }

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceCall",
        "params": []interface{}{
            callObj,
            "latest",
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result CallTrace `json:"result"`
    }
    json.Unmarshal(data, &response)

    trace := response.Result
    gasUsed, _ := strconv.ParseInt(trace.GasUsed[2:], 16, 64)

    fmt.Printf("Type: %s\n", trace.Type)
    fmt.Printf("Gas used: %d\n", gasUsed)

    if trace.Error != "" {
        fmt.Printf("Error: %s\n", trace.Error)
        fmt.Printf("Revert reason: %s\n", trace.RevertReason)
    } else {
        fmt.Printf("Output: %s\n", trace.Output)
    }

    // Print sub-calls
    for _, call := range trace.Calls {
        subGas, _ := strconv.ParseInt(call.GasUsed[2:], 16, 64)
        fmt.Printf("  -> %s to %s (%d gas)\n", call.Type, call.To, subGas)
    }
}
```

## Common Use Cases

### 1. Pre-Flight Transaction Simulation

Test a transaction before sending it on Zora to catch reverts and estimate costs:

```javascript
async function simulateTransaction(provider, txParams) {
  // Use callTracer to see the full call tree
  const trace = await provider.send('debug_traceCall', [
    {
      from: txParams.from,
      to: txParams.to,
      data: txParams.data,
      value: txParams.value || '0x0',
      gas: txParams.gasLimit || '0x1e8480' // 2M gas default
    },
    'latest',
    { tracer: 'callTracer' }
  ]);

  const gasUsed = parseInt(trace.gasUsed, 16);

  if (trace.error) {
    console.error('Transaction would revert!');
    console.error(`  Error: ${trace.error}`);
    console.error(`  Reason: ${trace.revertReason || 'unknown'}`);
    console.error(`  Gas wasted: ${gasUsed}`);
    return { success: false, error: trace.error, revertReason: trace.revertReason, gasUsed };
  }

  // Analyze internal calls for unexpected behavior
  const allCalls = flattenCalls(trace);
  const delegateCalls = allCalls.filter(c => c.type === 'DELEGATECALL');
  const creates = allCalls.filter(c => c.type === 'CREATE' || c.type === 'CREATE2');

  console.log('Simulation results:');
  console.log(`  Gas used: ${gasUsed}`);
  console.log(`  Internal calls: ${allCalls.length}`);
  console.log(`  Delegate calls: ${delegateCalls.length}`);
  console.log(`  Contract creations: ${creates.length}`);

  return { success: true, gasUsed, trace };
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 2. Gas Optimization Analysis

Identify the most expensive opcodes in a contract call on Zora:

```javascript
async function analyzeGasHotspots(provider, callObj) {
  // Use default opcode tracer for step-by-step gas analysis
  const trace = await provider.send('debug_traceCall', [
    callObj,
    'latest',
    { disableStorage: false, enableReturnData: true }
  ]);

  const opcodeGas = {};

  for (const log of trace.structLogs) {
    if (!opcodeGas[log.op]) {
      opcodeGas[log.op] = { count: 0, totalGas: 0 };
    }
    opcodeGas[log.op].count++;
    opcodeGas[log.op].totalGas += log.gasCost;
  }

  // Sort by total gas cost
  const sorted = Object.entries(opcodeGas)
    .map(([op, stats]) => ({ op, ...stats, avgGas: Math.round(stats.totalGas / stats.count) }))
    .sort((a, b) => b.totalGas - a.totalGas);

  console.log('Gas hotspots:');
  console.log('Op'.padEnd(15), 'Count'.padStart(8), 'Total Gas'.padStart(12), 'Avg Gas'.padStart(10));
  for (const entry of sorted.slice(0, 10)) {
    console.log(
      entry.op.padEnd(15),
      String(entry.count).padStart(8),
      String(entry.totalGas).padStart(12),
      String(entry.avgGas).padStart(10)
    );
  }

  // Identify SSTORE/SLOAD hotspots (most expensive storage operations)
  const storageOps = trace.structLogs.filter(
    log => log.op === 'SSTORE' || log.op === 'SLOAD'
  );
  console.log(`\nStorage operations: ${storageOps.length} (${storageOps.filter(s => s.op === 'SSTORE').length} writes)`);

  return { opcodeGas: sorted, totalSteps: trace.structLogs.length, totalGas: trace.gas };
}
```

### 3. Security Analysis of Contract Interactions

Detect potentially dangerous patterns when calling a contract on Zora:

```python
import requests

def security_trace_call(call_object, block='latest'):
    response = requests.post('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceCall',
        'params': [call_object, block, {'tracer': 'callTracer'}],
        'id': 1
    })
    trace = response.json()['result']

    warnings = []
    all_calls = flatten_calls(trace)

    for call in all_calls:
        # Detect unexpected delegate calls
        if call['type'] == 'DELEGATECALL':
            warnings.append(f'DELEGATECALL to {call["to"]} - could modify caller storage')

        # Detect value transfers to unexpected addresses
        value = int(call.get('value', '0x0'), 16)
        if value > 0 and call['to'] != call_object.get('to', '').lower():
            warnings.append(
                f'Value transfer of {value} wei to unexpected address {call["to"]}'
            )

        # Detect selfdestruct (CALL with no input to EOA after value)
        if call.get('error'):
            warnings.append(f'Internal revert at {call["to"]}: {call["error"]}')

    if trace.get('error'):
        print(f'TOP-LEVEL REVERT: {trace["error"]}')
        if trace.get('revertReason'):
            print(f'  Reason: {trace["revertReason"]}')
    else:
        gas_used = int(trace['gasUsed'], 16)
        print(f'Call succeeded: {gas_used} gas used')

    if warnings:
        print(f'\nSecurity warnings ({len(warnings)}):')
        for w in warnings:
            print(f'  - {w}')
    else:
        print('No security warnings detected')

    return {'success': not trace.get('error'), 'warnings': warnings}

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

# Example: analyze a token approval
security_trace_call({
    'from': '0x1234567890abcdef1234567890abcdef12345678',
    'to': '0x4200000000000000000000000000000000000006',
    'data': '0x095ea7b3000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
})
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/zora/eth_call) - Execute a call without trace (returns only the result, not execution details)
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zora/debug_traceTransaction) - Trace an already-executed transaction by hash
- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas for a call (without trace details)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zora/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/zora/debug_traceBlockByHash) - Trace all transactions in a block by hash

---

## debug_traceTransaction - Zora RPC Method

# debug_traceTransaction - Zora RPC Method

Traces a transaction execution on Zora by transaction hash.

This method requires an archive node. It is not available on full nodes.

## When to Use This Method

- **Analyze transaction execution step-by-step** - Trace every opcode and internal call in a completed transaction for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Debug failed transactions** - Pinpoint the exact opcode and call depth where a transaction reverted on Zora
- **Examine internal call traces** - Follow the full call tree including delegate calls and contract creations
- **Gas usage profiling** - Measure gas consumption per opcode to identify optimization opportunities

## Best Practices

- Requires archive node access; not available on standard full nodes
- Traces can be very large for complex transactions with many internal calls
- Use tracer options like `onlyTopCall` or `callTracer` to limit output size
- Store traces off-chain for analysis rather than querying repeatedly

## Request Parameters

- `txHash` (`DATA, required`): 32-byte transaction hash
- `tracerConfig` (`Object, optional`): Tracer configuration

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea", {"tracer": "callTracer"}],
  "id": 1
}
```

## Response Fields

- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`string, required`): Sender address
- `to` (`string, required`): Receiver address
- `gas` (`string, required`): Gas provided for the call (hex)
- `gasUsed` (`string, required`): Gas consumed by the call (hex)
- `input` (`string, required`): Call data (hex)
- `output` (`string, required`): Return data (hex), present on success
- `value` (`string, required`): Value transferred in wei (hex)
- `error` (`string, required`): Revert reason, present on failure
- `calls` (`array, required`): Nested internal calls

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0xabc...",
    "to": "0xdef...",
    "gas": "0x13880",
    "gasUsed": "0x5208",
    "input": "0x",
    "output": "0x",
    "value": "0x0"
  }
}
```

## Tracer Options

- `{}` - Default opcode tracer (verbose)
- `{ tracer: "callTracer" }` - Call tree tracer
- `{ tracer: "prestateTracer" }` - Pre-state tracer

## Code Examples

cURL
JavaScript
Python

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": ["0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea", {"tracer": "callTracer"}],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea';

// Call tracer - shows internal calls
const callTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);
console.log('Type:', callTrace.type);
console.log('From:', callTrace.from);
console.log('To:', callTrace.to);
console.log('Gas used:', parseInt(callTrace.gasUsed, 16));

// Prestate tracer - shows state before execution
const prestateTrace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'prestateTracer' }
]);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea'

# Call tracer
trace = w3.provider.make_request('debug_traceTransaction', [
    tx_hash,
    {'tracer': 'callTracer'}
])
print(f'Trace type: {trace["result"]["type"]}')
print(f'Gas used: {int(trace["result"]["gasUsed"], 16)}')
```

## Related Methods

- [`debug_traceCall`](https://www.dwellir.com/docs/zora/debug_traceCall) - Trace without executing
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/zora/debug_traceBlockByNumber) - Trace entire block

---

## eth_accounts - Zora RPC Method

# eth_accounts - Zora RPC Method

Returns a list of addresses owned by the client on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## Important Note

On public RPC endpoints like Dwellir, `eth_accounts` returns an empty array because the node does not hold any private keys. This method is primarily useful for:

- Local development nodes (Ganache, Hardhat, Anvil)
- Private nodes with managed accounts
- Wallet provider connections (MetaMask injects accounts)

## When to Use This Method

`eth_accounts` is relevant for NFT creators, digital artists, brands, and onchain media builders in specific scenarios:

- **Development Testing** - Retrieve test accounts from local nodes
- **Wallet Detection** - Check if a wallet provider has connected accounts
- **Client Verification** - Confirm node account access capabilities

## Best Practices

- Most public providers disable this method for security reasons; expect an empty array return
- Use wallet libraries (ethers.js, web3.py) for account management instead of relying on node-side accounts
- An empty array return is normal on managed providers and does not indicate an error condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_accounts",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Array<DATA>, required`): List of 20-byte account addresses owned by the client

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": []
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_accounts",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_accounts',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Accounts:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const accounts = await provider.listAccounts();
console.log('Accounts:', accounts);
```

```python
import requests

def get_accounts():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_accounts',
            'params': [],
            'id': 1
        }
    )
    return response.json()['result']

accounts = get_accounts()
print(f'Accounts: {accounts}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Accounts: {w3.eth.accounts}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var accounts []string
    err = client.CallContext(context.Background(), &accounts, "eth_accounts")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Accounts: %v\n", accounts)
}
```

## Common Use Cases

### 1. Development Environment Detection

Check if running against a development node with test accounts:

```javascript
async function isDevEnvironment(provider) {
  const accounts = await provider.listAccounts();
  return accounts.length > 0;
}

const isDev = await isDevEnvironment(provider);
if (isDev) {
  console.log('Development environment detected');
}
```

### 2. Wallet Connection Check

Verify wallet provider has connected accounts:

```javascript
async function checkWalletConnection() {
  if (typeof window.ethereum === 'undefined') {
    return { connected: false, reason: 'No wallet detected' };
  }

  const accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  return {
    connected: accounts.length > 0,
    accounts: accounts
  };
}
```

### 3. Fallback Account Selection

Use first available account or request connection:

```javascript
async function getActiveAccount() {
  // Check existing connections
  let accounts = await window.ethereum.request({
    method: 'eth_accounts'
  });

  // Request connection if no accounts
  if (accounts.length === 0) {
    accounts = await window.ethereum.request({
      method: 'eth_requestAccounts'
    });
  }

  return accounts[0] || null;
}
```

## Related Methods

- [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102) - Request wallet connection (browser wallets)
- [`eth_getBalance`](https://www.dwellir.com/docs/zora/eth_getBalance) - Get account balance
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/zora/eth_getTransactionCount) - Get account nonce

---

## eth_blockNumber - Zora RPC Method

# eth_blockNumber - Zora RPC Method

Returns the number of the most recent block on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_blockNumber` is fundamental for NFT creators, digital artists, brands, and onchain media builders:

- **Syncing Applications** - Keep your dApp in sync with the latest Zora blockchain state
- **Transaction Monitoring** - Verify confirmations by comparing block numbers
- **Event Filtering** - Set the correct block range for querying logs on low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Health Checks** - Monitor node connectivity and sync status

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the current block number

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5BAD55"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const blockNumber = parseInt(result, 16);
console.log('Zora block:', blockNumber);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockNumber = await provider.getBlockNumber();
console.log('Zora block:', blockNumber);
```

```python
import requests

def get_block_number():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_blockNumber',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

block_number = get_block_number()
print(f'Zora block: {block_number}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Zora block: {w3.eth.block_number}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zora block: %d\n", blockNumber)
}
```

## Common Use Cases

### 1. Block Confirmation Counter

Monitor transaction confirmations on Zora:

```javascript
async function getConfirmations(provider, txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockNumber) return 0;

  const currentBlock = await provider.getBlockNumber();
  return currentBlock - tx.blockNumber + 1;
}

// Wait for specific confirmations
async function waitForConfirmations(provider, txHash, confirmations = 6) {
  let currentConfirmations = 0;

  while (currentConfirmations < confirmations) {
    currentConfirmations = await getConfirmations(provider, txHash);
    console.log(`Confirmations: ${currentConfirmations}/${confirmations}`);
    await new Promise(r => setTimeout(r, 2000));
  }

  return true;
}
```

### 2. Event Log Filtering

Query events from recent blocks on Zora:

```javascript
async function getRecentEvents(provider, contract, eventName, blockRange = 100) {
  const currentBlock = await provider.getBlockNumber();
  const fromBlock = currentBlock - blockRange;

  const filter = contract.filters[eventName]();
  const events = await contract.queryFilter(filter, fromBlock, currentBlock);

  return events;
}
```

### 3. Node Health Monitoring

Check if your Zora node is synced:

```javascript
async function checkNodeHealth(provider) {
  try {
    const blockNumber = await provider.getBlockNumber();
    const block = await provider.getBlock(blockNumber);

    const now = Date.now() / 1000;
    const blockAge = now - block.timestamp;

    if (blockAge > 60) {
      console.warn(`Node may be behind. Last block was ${blockAge}s ago`);
      return false;
    }

    console.log(`Node healthy. Latest block: ${blockNumber}`);
    return true;
  } catch (error) {
    console.error('Node unreachable:', error);
    return false;
  }
}
```

## Performance Optimization

### Caching Strategy

Cache block numbers to reduce API calls:

```javascript
class BlockNumberCache {
  constructor(ttl = 2000) {
    this.cache = null;
    this.timestamp = 0;
    this.ttl = ttl;
  }

  async get(provider) {
    const now = Date.now();

    if (this.cache && (now - this.timestamp) < this.ttl) {
      return this.cache;
    }

    this.cache = await provider.getBlockNumber();
    this.timestamp = now;
    return this.cache;
  }

  invalidate() {
    this.cache = null;
    this.timestamp = 0;
  }
}

const blockCache = new BlockNumberCache();
```

### Batch Requests

Combine with other calls for efficiency:

```javascript
const batch = [
  { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
  { jsonrpc: '2.0', method: 'eth_gasPrice', params: [], id: 2 },
  { jsonrpc: '2.0', method: 'eth_chainId', params: [], id: 3 }
];

const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(batch)
});

const results = await response.json();
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Get full block details by number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zora/eth_getBlockByHash) - Get block details by hash
- [`eth_syncing`](https://www.dwellir.com/docs/zora/eth_syncing) - Check if node is still syncing

---

## eth_call - Zora RPC Method

# eth_call - Zora RPC Method

Executes a new message call immediately without creating a transaction on Zora. Used for reading smart contract state.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

The `eth_call` method serves these key scenarios for NFT creators, digital artists, brands, and onchain media builders:

- **Read smart contract state** - Execute view and pure functions to query token balances, DeFi positions, and protocol data without spending gas
- **Simulate transactions** - Test contract interactions before submitting them on-chain, avoiding failed transactions and wasted gas costs
- **Multi-call aggregator queries** - Batch multiple read calls into a single request using multicall contracts, reducing API overhead on Zora
- **MEV and arbitrage analysis** - Simulate transaction bundles to evaluate profitable opportunities before execution on low-cost NFT minting, onchain media monetization, and creator-owned token economies

## Common Use Cases

### 1. Read ERC20 Token Balance

Query an ERC20 token contract to retrieve the balance for a specific wallet address using the `balanceOf(address)` function selector encoded as calldata. The selector is derived from the first 4 bytes of keccak256("balanceOf(address)"), followed by the 32-byte zero-padded address argument.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const walletAddress = '0x4200000000000000000000000000000000000006';

const balanceSelector = '0x70a08231' + walletAddress.slice(2).padStart(64, '0');

async function getTokenBalance() {
  const result = await provider.call({
    to: tokenAddress,
    data: balanceSelector
  });
  console.log('Balance (raw):', BigInt(result).toString());
  return result;
}

getTokenBalance();
```

### 2. Query DeFi Protocol State

Read protocol reserves, price oracles, or user positions from DeFi contracts on Zora. Each protocol exposes view functions that let you inspect pool state without modifying it - ideal for building analytics dashboards and trading bots.

```javascript
import { JsonRpcProvider, Interface } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const poolAbi = [
  'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestamp)'
];
const poolInterface = new Interface(poolAbi);
const poolAddress = '0x4200000000000000000000000000000000000006';

async function getPoolReserves() {
  const data = poolInterface.encodeFunctionData('getReserves');
  const result = await provider.call({ to: poolAddress, data });
  const decoded = poolInterface.decodeFunctionResult('getReserves', result);
  console.log('Reserve 0:', decoded[0].toString());
  console.log('Reserve 1:', decoded[1].toString());
  return decoded;
}

getPoolReserves();
```

### 3. Simulate a Swap Before Execution

Before committing a token swap, call the router contract's quote function to calculate the expected output. This lets you validate slippage tolerance and compare rates across DEXes without risking gas on a failed trade.

```javascript
import { JsonRpcProvider, Interface, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const routerAddress = '0x4200000000000000000000000000000000000006';

const routerAbi = [
  'function getAmountsOut(uint amountIn, address[] calldata path) view returns (uint[] amounts)'
];
const routerInterface = new Interface(routerAbi);

async function simulateSwap(amountIn, tokenIn, tokenOut) {
  const data = routerInterface.encodeFunctionData('getAmountsOut', [
    parseEther(amountIn),
    [tokenIn, tokenOut]
  ]);
  const result = await provider.call({ to: routerAddress, data });
  const decoded = routerInterface.decodeFunctionResult('getAmountsOut', result);
  console.log('Expected output:', decoded[0][1].toString());
  return decoded[0][1];
}

simulateSwap('1.0', '0xTokenA...', '0xTokenB...');
```

## Best Practices

- Use `latest` for current-state reads and `pending` for pre-confirmation simulation on Zora
- Encode function selectors correctly: take the first 4 bytes of the keccak256 hash of the function signature
- Handle revert errors gracefully by parsing the revert reason from the error response data
- For batch reads, use multicall contracts to combine multiple `eth_call` requests into a single RPC call
- `eth_call` does not consume gas, making it ideal for unlimited read queries on Zora

## Request Parameters

- `from` (`DATA, optional`): 20-byte address executing the call
- `to` (`DATA, required`): 20-byte contract address
- `gas` (`QUANTITY, optional`): Gas limit for the call
- `gasPrice` (`QUANTITY, optional`): Gas price in wei
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, required`): Encoded function call data
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_call",
  "params": [
    {
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    },
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The return value of the executed contract function

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Call ERC20 balanceOf function
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call",
    "params": [{
      "to": "0x4200000000000000000000000000000000000006",
      "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006"
    }, "latest"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// ERC20 ABI for common functions
const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

// Read ERC20 token balance
async function getTokenBalance(tokenAddress, walletAddress) {
  const contract = new Contract(tokenAddress, ERC20_ABI, provider);
  const balance = await contract.balanceOf(walletAddress);
  const decimals = await contract.decimals();
  const symbol = await contract.symbol();

  return {
    raw: balance.toString(),
    formatted: (Number(balance) / Math.pow(10, decimals)).toFixed(4),
    symbol: symbol
  };
}

// Direct eth_call
async function directCall(to, data) {
  const result = await provider.call({ to, data });
  return result;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_erc20_balance(token_address, wallet_address):
    # balanceOf(address) selector
    function_signature = "balanceOf(address)"
    function_selector = w3.keccak(text=function_signature)[:4].hex()

    # Encode address parameter
    encoded_address = wallet_address[2:].lower().zfill(64)
    data = function_selector + encoded_address

    # Make the call
    result = w3.eth.call({
        'to': token_address,
        'data': data
    })

    return int(result.hex(), 16)

balance = get_erc20_balance(
    '0x4200000000000000000000000000000000000006',
    '0x4200000000000000000000000000000000000006'
)
print(f'Balance: {balance}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    data := common.FromHex("0x70a082310000000000000000000000004200000000000000000000000000000000000006")

    msg := ethereum.CallMsg{
        To:   &contractAddress,
        Data: data,
    }

    result, err := client.CallContract(context.Background(), msg, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: 0x%x\n", result)
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas for transaction
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Send actual transaction

---

## eth_chainId - Zora RPC Method

# eth_chainId - Zora RPC Method

Returns the chain ID used for transaction signing on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_chainId` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **EIP-155 Transaction Signing** -- Include the chain ID in transaction signatures to prevent replay attacks across different networks
- **Multi-Chain Application Routing** -- Detect which network the RPC endpoint serves and configure application logic accordingly
- **Wallet Integration** -- Verify users are connected to the expected network before prompting transaction approval
- **Cross-Chain Security** -- Validate chain identity before bridging assets or relaying messages on low-cost NFT minting, onchain media monetization, and creator-owned token economies

## Common Use Cases

### 1. Multi-Network Connection Guard

Reject connections to unexpected networks before any transaction is sent:

```javascript
import { JsonRpcProvider, BrowserProvider } from 'ethers';

async function guardNetwork(provider, allowedChainIds) {
  const network = await provider.getNetwork();
  const chainId = Number(network.chainId);
  
  if (!allowedChainIds.includes(chainId)) {
    throw new Error(
      `Wrong network: connected to chain ${chainId}, expected one of [${allowedChainIds}]`
    );
  }
  
  console.log(`Connected to chain ${chainId}`);
  return chainId;
}

// Example: only allow Ethereum mainnet (1) and Arbitrum (42161)
await guardNetwork(provider, [1, 42161]);
```

### 2. Wallet Network Switcher

Detect the current chain and prompt wallet to switch if needed:

```javascript
async function ensureCorrectChain(walletProvider, targetChainId, chainParams) {
  const currentChainId = await walletProvider.send('eth_chainId', []);
  const currentId = parseInt(currentChainId, 16);
  
  if (currentId !== targetChainId) {
    try {
      await walletProvider.send('wallet_switchEthereumChain', [
        { chainId: '0x' + targetChainId.toString(16) }
      ]);
    } catch (switchError) {
      // Chain not added to wallet -- add it
      if (switchError.code === 4902) {
        await walletProvider.send('wallet_addEthereumChain', [chainParams]);
      } else {
        throw switchError;
      }
    }
    
    console.log(`Switched to chain ${targetChainId}`);
  } else {
    console.log(`Already on chain ${targetChainId}`);
  }
  
  return targetChainId;
}
```

### 3. Chain-Aware Configuration Loader

Dynamically load chain-specific contract addresses and settings:

```python
from web3 import Web3

def load_chain_config(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))
    chain_id = w3.eth.chain_id
    
    configs = {
        1: {
            'name': 'Ethereum Mainnet',
            'uniswap_router': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'explorer': 'https://etherscan.io',
            'native_symbol': 'ETH'
        },
        137: {
            'name': 'Polygon',
            'uniswap_router': '0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff',
            'explorer': 'https://polygonscan.com',
            'native_symbol': 'MATIC'
        },
        42161: {
            'name': 'Arbitrum One',
            'uniswap_router': '0xE592427A0AEce92De3Edee1F18E0157C05861564',
            'explorer': 'https://arbiscan.io',
            'native_symbol': 'ETH'
        }
    }
    
    if chain_id not in configs:
        raise ValueError(f'Unsupported chain ID: {chain_id}')
    
    config = configs[chain_id]
    print(f'Loaded config for {config["name"]} (chain {chain_id})')
    return {'chain_id': chain_id, **config}
```

## Best Practices

- Use `eth_chainId` (not `net_version`) for EIP-155 transaction signing -- chain ID is the canonical signing value
- Cache the chain ID at application startup -- it does not change during a session
- For browser wallet dApps, use `wallet_switchEthereumChain` and `wallet_addEthereumChain` to guide users to the correct network
- Some L2 chains share the same chain ID as their L1 -- always combine chain ID checks with additional endpoint verification
- Return value is a hex-encoded integer -- parse with `parseInt(result, 16)` before using

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_chainId",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Chain ID in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_chainId",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const network = await provider.getNetwork();
console.log('Chain ID:', network.chainId);

// Verify network before transaction
async function verifyNetwork(expectedChainId) {
  const network = await provider.getNetwork();
  if (network.chainId !== BigInt(expectedChainId)) {
    throw new Error(`Wrong network. Expected ${expectedChainId}, got ${network.chainId}`);
  }
  return true;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

chain_id = w3.eth.chain_id
print(f'Chain ID: {chain_id}')

# Verify network
def verify_network(expected_chain_id):
    chain_id = w3.eth.chain_id
    if chain_id != expected_chain_id:
        raise ValueError(f'Wrong network. Expected {expected_chain_id}, got {chain_id}')
    return True
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Chain ID: %d\n", chainID)
}
```

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/zora/net_version) - Get network version
- [`eth_syncing`](https://www.dwellir.com/docs/zora/eth_syncing) - Check sync status

---

## eth_coinbase - Zora RPC Method

# eth_coinbase - Zora RPC Method

Checks the legacy `eth_coinbase` compatibility method on Zora. Public endpoints may return an address, `unimplemented`, or another unsupported-method response depending on the client behind the endpoint.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

> **Note:** Treat `eth_coinbase` as a legacy compatibility probe. On shared infrastructure, this method may return `unimplemented` or another unsupported-method error, so it is not a dependable production signal.

## When to Use This Method

`eth_coinbase` is relevant for NFT creators, digital artists, brands, and onchain media builders when you need to:

- **Check client compatibility** - Confirm whether the connected client still exposes `eth_coinbase`
- **Audit migration assumptions** - Remove Ethereum-era assumptions that every endpoint reports an etherbase address
- **Harden integrations** - Fall back to supported identity or chain-status methods when `eth_coinbase` is unavailable

## Best Practices

- Returns the node's mining address; most providers return their own address or `0x0`
- Not a reliable way to identify validators or block producers on modern chains
- Use eth\_accounts for listing user-managed accounts
- Treat unimplemented or method-not-found responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_coinbase",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (20 bytes), required`): The reported compatibility address when the client exposes eth_coinbase

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_coinbase",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_coinbase',
    params: [],
    id: 1
  })
});

const { result, error } = await response.json();

if (error) {
  console.log('No coinbase configured:', error.message);
} else {
  console.log('Zora coinbase:', result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const coinbase = await provider.send('eth_coinbase', []);
  console.log('Zora coinbase:', coinbase);
} catch (err) {
  console.log('Coinbase not configured on this node');
}
```

```python
import requests

def get_coinbase():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_coinbase',
            'params': [],
            'id': 1
        }
    )
    data = response.json()
    if 'error' in data:
        return None
    return data['result']

coinbase = get_coinbase()
if coinbase:
    print(f'Zora coinbase: {coinbase}')
else:
    print('No coinbase configured on this node')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Zora coinbase: {w3.eth.coinbase}')
except Exception:
    print('Coinbase not available')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var coinbase common.Address
    err = client.CallContext(context.Background(), &coinbase, "eth_coinbase")
    if err != nil {
        fmt.Println("Coinbase not configured:", err)
        return
    }

    fmt.Printf("Zora coinbase: %s\n", coinbase.Hex())
}
```

## Common Use Cases

### 1. Validator Configuration Verification

Verify that a node's coinbase matches the expected reward address:

```javascript
async function verifyCoinbase(provider, expectedAddress) {
  try {
    const coinbase = await provider.send('eth_coinbase', []);

    if (coinbase.toLowerCase() === expectedAddress.toLowerCase()) {
      console.log('Coinbase address verified');
      return true;
    } else {
      console.warn(`Coinbase mismatch: expected ${expectedAddress}, got ${coinbase}`);
      return false;
    }
  } catch {
    console.error('Could not retrieve coinbase - may not be configured');
    return false;
  }
}
```

### 2. Block Producer Identification

Identify the coinbase address alongside block production details:

```javascript
async function getProducerInfo(provider) {
  const [coinbase, mining, hashrate] = await Promise.allSettled([
    provider.send('eth_coinbase', []),
    provider.send('eth_mining', []),
    provider.send('eth_hashrate', [])
  ]);

  return {
    coinbase: coinbase.status === 'fulfilled' ? coinbase.value : 'not configured',
    isMining: mining.status === 'fulfilled' ? mining.value : false,
    hashrate: hashrate.status === 'fulfilled' ? parseInt(hashrate.value, 16) : 0
  };
}
```

### 3. Multi-Node Coinbase Audit

Audit coinbase addresses across a fleet of Zora nodes:

```javascript
async function auditCoinbases(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      try {
        const coinbase = await provider.send('eth_coinbase', []);
        return { endpoint, coinbase, configured: true };
      } catch {
        return { endpoint, coinbase: null, configured: false };
      }
    })
  );

  const unique = new Set(results.filter(r => r.configured).map(r => r.coinbase));
  console.log(`Found ${unique.size} unique coinbase address(es) across ${endpoints.length} nodes`);

  return results;
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/zora/eth_mining) - Check if the node is actively mining
- [`eth_hashrate`](https://www.dwellir.com/docs/zora/eth_hashrate) - Get the mining hash rate
- [`eth_accounts`](https://www.dwellir.com/docs/zora/eth_accounts) - List all accounts managed by the node

---

## eth_estimateGas - Zora RPC Method

# eth_estimateGas - Zora RPC Method

Estimates the gas necessary to execute a transaction on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

The `eth_estimateGas` method serves these key scenarios for NFT creators, digital artists, brands, and onchain media builders:

- **Calculate gas budgets** - Determine how much gas a transaction requires before submitting, helping set accurate gas limits for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Estimate costs for complex interactions** - Predict gas requirements for multi-step contract calls, such as DeFi composability chains across multiple protocols
- **Compare gas efficiency** - Evaluate gas consumption between different contract implementations to identify the most cost-effective approach on Zora
- **Prevent out-of-gas failures** - Verify that the gas limit is sufficient for the intended transaction to avoid wasted gas on reverted transactions

## Common Use Cases

### 1. Estimate Gas for an ERC20 Transfer

Before sending an ERC20 transfer, estimate the gas cost to ensure you set a sufficient limit. Token transfers typically consume more gas than native ETH transfers because they execute contract logic - most ERC20 implementations use around 45,000-65,000 gas per transfer.

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const erc20Abi = [
  'function transfer(address to, uint256 amount) returns (bool)'
];
const tokenContract = new Contract('0x4200000000000000000000000000000000000006', erc20Abi, provider);

async function estimateTransferGas(to, amount) {
  const gasEstimate = await tokenContract.transfer.estimateGas(to, amount);
  console.log('Estimated gas for transfer:', gasEstimate.toString());
  return gasEstimate;
}

const gas = await estimateTransferGas('0x4200000000000000000000000000000000000006', '1000000000000000000');
```

### 2. Simulate Contract Deployment Cost

Estimate how much gas a contract deployment will consume before submitting the creation transaction. The deployment cost depends on the bytecode size and constructor arguments - use this to budget for contract deployments on Zora.

```javascript
import { JsonRpcProvider, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function estimateDeploymentGas(bytecode, abi, constructorArgs) {
  const factory = new ContractFactory(abi, bytecode, provider);
  const deployTx = await factory.getDeployTransaction(...constructorArgs);
  const gasEstimate = await provider.estimateGas(deployTx);
  console.log('Estimated deployment gas:', gasEstimate.toString());
  return gasEstimate;
}

const estimatedGas = await estimateDeploymentGas(
  '0x608060...',
  ['constructor(uint256)'],
  [42]
);
```

### 3. Build Transaction with Gas Buffer

Apply a safety buffer to the estimated gas to account for minor state changes between estimation and execution. The recommended buffer varies by chain - fast, low-congestion chains like Zora may need only 20%, while complex DeFi interactions benefit from 50%.

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildSafeTransaction(from, to, value, contractData) {
  const [nonce, feeData] = await Promise.all([
    provider.getTransactionCount(from),
    provider.getFeeData()
  ]);

  const tx = {
    from,
    to,
    value: parseEther(value),
    data: contractData || '0x',
    nonce,
    maxFeePerGas: feeData.maxFeePerGas,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
  };

  const estimatedGas = await provider.estimateGas(tx);
  const bufferRatio = contractData ? 1.5 : 1.2;
  tx.gasLimit = BigInt(Math.floor(Number(estimatedGas) * bufferRatio));

  console.log('Estimated gas:', estimatedGas.toString());
  console.log('Buffered gas limit:', tx.gasLimit.toString());
  return tx;
}

const tx = await buildSafeTransaction(
  '0x4200000000000000000000000000000000000006',
  '0x4200000000000000000000000000000000000006',
  '0.01'
);
```

## Best Practices

- Add a 20-50% buffer to the estimated gas value for safety: simple transfers need less buffer, complex contract calls need more
- If the estimate reverts, the transaction would also revert: fix the underlying issue rather than increasing gas
- `eth_estimateGas` runs against the current state at block `latest`: state changes between estimation and execution can alter the actual gas requirement
- For EIP-1559 chains, combine `eth_estimateGas` with `eth_feeHistory` to calculate the accurate total transaction cost in native currency
- L2 chains may return significantly different gas estimates than L1 for the same contract interaction

## Request Parameters

- `from` (`DATA, optional`): Sender address
- `to` (`DATA, optional`): Recipient address
- `gas` (`QUANTITY, optional`): Gas limit
- `gasPrice` (`QUANTITY, optional`): Gas price
- `value` (`QUANTITY, optional`): Value in wei
- `data` (`DATA, optional`): Transaction data

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [{
    "from": "0x4200000000000000000000000000000000000006",
    "to": "0x4200000000000000000000000000000000000006",
    "value": "0x1"
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Estimated gas amount in hexadecimal

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x5208"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [{
      "from": "0x4200000000000000000000000000000000000006",
      "to": "0x4200000000000000000000000000000000000006",
      "value": "0x1"
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Estimate simple transfer
async function estimateTransfer(to, value) {
  const gasEstimate = await provider.estimateGas({
    to: to,
    value: parseEther(value)
  });

  console.log('Estimated gas:', gasEstimate.toString());
  return gasEstimate;
}

// Estimate contract call
async function estimateContractCall(contract, method, args) {
  const gasEstimate = await contract[method].estimateGas(...args);
  console.log('Estimated gas:', gasEstimate.toString());

  // Add 20% buffer for safety
  return gasEstimate * 120n / 100n;
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def estimate_transfer(to, value_in_ether):
    gas_estimate = w3.eth.estimate_gas({
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether')
    })

    print(f'Estimated gas: {gas_estimate}')
    return gas_estimate

def estimate_contract_call(contract, method, args):
    func = getattr(contract.functions, method)
    gas_estimate = func(*args).estimate_gas()

    # Add 20% buffer
    return int(gas_estimate * 1.2)

# Estimate simple transfer
gas = estimate_transfer('0x4200000000000000000000000000000000000006', 0.1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    msg := ethereum.CallMsg{
        To:    &toAddress,
        Value: big.NewInt(1000000000000000000),
    }

    gasLimit, err := client.EstimateGas(context.Background(), msg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Estimated gas: %d\n", gasLimit)
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zora/eth_gasPrice) - Get current gas price
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Send transaction

---

## eth_estimateL1Fee - Estimate L1 data posting fee

# eth_estimateL1Fee - Estimate L1 data posting fee

Estimate L1 data posting fee on the Zora network.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_estimateL1Fee",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): The return value depends on the specific method being called.

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_estimateL1Fee",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_estimateL1Fee',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## eth_feeHistory - Zora RPC Method

# eth_feeHistory - Zora RPC Method

Returns historical gas fee data on Zora, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for NFT creators, digital artists, brands, and onchain media builders:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Zora without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Zora.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Zora) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zora/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/zora/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_gasPrice - Zora RPC Method

# eth_gasPrice - Zora RPC Method

Returns the current gas price on Zora in wei.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

The `eth_gasPrice` method serves these key scenarios for NFT creators, digital artists, brands, and onchain media builders:

- **Set gas price for legacy transactions** - Use the returned wei value as the `gasPrice` field in legacy (pre-EIP-1559) transactions on Zora
- **Monitor network congestion** - Track gas price fluctuations to determine the best time to submit transactions for lower fees
- **Estimate transaction costs** - Multiply gas price by estimated gas units to calculate the total cost before sending any transaction
- **Build gas price oracles** - Feed real-time gas price data into fee estimation UIs, automated trading bots, and wallet applications

## Common Use Cases

### 1. Calculate Total Transaction Cost

Multiply the current gas price by the estimated gas for a transaction to determine the total cost in the native currency of Zora. This lets users see the expected fee before confirming any transaction.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function calculateTransactionCost(gasLimit) {
  const gasPrice = await provider.send('eth_gasPrice', []);
  const costWei = BigInt(gasPrice) * BigInt(gasLimit);
  const costEth = formatUnits(costWei, 'ether');
  console.log(`Gas price: ${formatUnits(gasPrice, 'gwei')} Gwei`);
  console.log(`Estimated cost: ${costEth} ETH`);
  return costEth;
}

await calculateTransactionCost(21000);
```

### 2. Build Dynamic Gas Price Strategy

Adjust gas prices dynamically based on current network conditions. During peak congestion on Zora, multiply the base gas price by 1.2-1.5x for faster inclusion; during quiet periods, use the raw gas price for the most economical confirmation.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getDynamicGasPrice(strategy = 'medium') {
  const baseGasPrice = BigInt(await provider.send('eth_gasPrice', []));
  const multipliers = { low: 1.0, medium: 1.2, high: 1.5 };

  const adjustedPrice = baseGasPrice * BigInt(Math.floor(multipliers[strategy] * 100)) / 100n;

  console.log(`Base gas price: ${formatUnits(baseGasPrice, 'gwei')} Gwei`);
  console.log(`Strategy (${strategy}): ${formatUnits(adjustedPrice, 'gwei')} Gwei`);
  return adjustedPrice;
}

await getDynamicGasPrice('medium');
```

### 3. Compare Gas Prices Across Chains

If your application supports multiple chains, compare gas prices to route transactions to the most cost-effective network. This is particularly useful for cross-chain bridges and multi-chain DeFi aggregators.

```javascript
const chains = {
  ethereum: 'https://eth.dwellir.com',
  polygon: 'https://polygon.dwellir.com',
  arbitrum: 'https://arb.dwellir.com'
};

async function compareGasPrices() {
  const results = {};
  for (const [name, rpcUrl] of Object.entries(chains)) {
    const provider = new JsonRpcProvider(rpcUrl);
    const gasPrice = await provider.send('eth_gasPrice', []);
    results[name] = {
      wei: BigInt(gasPrice).toString(),
      gwei: Number(BigInt(gasPrice)) / 1e9
    };
  }

  const sorted = Object.entries(results).sort((a, b) => a[1].gwei - b[1].gwei);
  console.log('Cheapest chain:', sorted[0][0], '-', sorted[0][1].gwei, 'Gwei');
  return results;
}

compareGasPrices();
```

## Best Practices

- Legacy gas price is a single number: for EIP-1559 transactions, prefer using `eth_feeHistory` combined with `eth_maxPriorityFeePerGas` instead
- The return value is in wei: divide by `1e9` to convert to gwei, which is the standard unit for gas price display
- Consider current network conditions on Zora: multiply by 1.2-1.5x for faster block inclusion during congestion
- Most modern chains use EIP-1559 exclusively: check if Zora supports dynamic fee transactions before relying on legacy gas price

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_gasPrice",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Current gas price in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3b9aca00"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_gasPrice",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const feeData = await provider.getFeeData();
const gasPrice = feeData.gasPrice;

console.log('Gas Price:', formatUnits(gasPrice, 'gwei'), 'Gwei');

// Calculate transaction cost
async function estimateTransactionCost(gasLimit) {
  const feeData = await provider.getFeeData();
  const cost = feeData.gasPrice * BigInt(gasLimit);
  return formatUnits(cost, 'ether');
}

const cost = await estimateTransactionCost(21000);
console.log('Transfer cost:', cost, 'ETH');
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

gas_price = w3.eth.gas_price
print(f'Gas Price: {w3.from_wei(gas_price, "gwei")} Gwei')

# Calculate transaction cost
def estimate_transaction_cost(gas_limit):
    gas_price = w3.eth.gas_price
    cost = gas_price * gas_limit
    return w3.from_wei(cost, 'ether')

cost = estimate_transaction_cost(21000)
print(f'Transfer cost: {cost} ETH')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    // Convert to Gwei
    gwei := new(big.Float).Quo(
        new(big.Float).SetInt(gasPrice),
        big.NewFloat(1e9),
    )

    fmt.Printf("Gas Price: %f Gwei\n", gwei)
}
```

## Related Methods

- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/zora/eth_maxPriorityFeePerGas) - Get priority fee (EIP-1559)
- [`eth_feeHistory`](https://www.dwellir.com/docs/zora/eth_feeHistory) - Get historical fee data
- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas needed

---

## eth_getBalance - Zora RPC Method

# eth_getBalance - Zora RPC Method

Returns the balance of a given address on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getBalance` is fundamental for NFT creators, digital artists, brands, and onchain media builders:

- **Wallet applications**: Display user balances and enable balance-dependent operations on Zora
- **Transaction validation**: Verify accounts have sufficient funds before submitting transactions to Zora
- **DeFi monitoring**: Track collateral positions, liquidity pools, and TVL across low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Accounting and reconciliation**: Cross-reference on-chain balances against off-chain ledger entries for financial reporting

## Request Parameters

- `address` (`DATA, required`): 20-byte address to check balance for
- `blockParameter` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBalance",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Integer of the current balance in wei (hexadecimal)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a055690d9db80000"
}
```

## Common Use Cases

### 1. Display Formatted Wallet Balance with Ether Conversion

Retrieve and display a human-readable balance for any address on Zora. Convert the wei result to ether client-side using your web3 library.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function displayBalance(address) {
  const balanceWei = await provider.getBalance(address);
  const balance = formatEther(balanceWei);
  console.log(`Balance: ${balance} Zora`);
  return balance;
}

displayBalance('0x4200000000000000000000000000000000000006');
```

### 2. Monitor Whale Wallet Activity with Polling and Threshold Alerts

Poll a high-value wallet on Zora at regular intervals. Trigger an alert when the balance crosses a defined threshold, useful for tracking DeFi movements or exchange hot wallet activity.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
address = '0x4200000000000000000000000000000000000006'
threshold_wei = w3.to_wei(100, 'ether')

def monitor_balance():
    previous_balance = w3.eth.get_balance(address)
    while True:
        time.sleep(15)
        current_balance = w3.eth.get_balance(address)
        if abs(current_balance - previous_balance) > threshold_wei:
            print(f'Balance changed by more than 100 Zora')
        if current_balance > w3.to_wei(1000, 'ether'):
            print(f'Whale alert: wallet exceeds 1000 Zora')
        previous_balance = current_balance

monitor_balance()
```

### 3. Historical Balance Tracking Using Block Tags

Query an account's balance at a specific block height to build a historical balance timeline. This is essential for audit trails, tax reporting, and analyzing wallet behavior over time on Zora.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Query balance at a specific block number
    blockNumber := big.NewInt(1000000)
    historicalBalance, _ := client.BalanceAt(context.Background(), address, blockNumber)
    fmt.Printf("Historical balance at block 1,000,000: %s wei\n", historicalBalance.String())

    // Query latest balance for comparison
    currentBalance, _ := client.BalanceAt(context.Background(), address, nil)
    change := new(big.Int).Sub(currentBalance, historicalBalance)
    fmt.Printf("Balance change: %s wei\n", change.String())
}
```

## Best Practices

- **Cache balances with short TTL**: Set a 2-5 second cache duration for balance queries to reduce RPC calls while keeping data fresh enough for most UI use cases
- **Convert wei to ether client-side**: Use `formatEther` (ethers.js) or `fromWei` (web3.py) rather than relying on node-side conversion, which the JSON-RPC does not provide
- **Use `pending` tag cautiously**: Balances returned with the `pending` block tag may reflect unconfirmed state changes and differ from finalized on-chain values
- **For batch balance queries, use `eth_call` with multicall**: When querying balances for many addresses, bundle them through a multicall contract to reduce individual RPC round-trips

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const balanceWei = await provider.getBalance(address);
const balance = formatEther(balanceWei);

console.log(`Balance: ${balance}`);

// Get balance at specific block
const historicalBalance = await provider.getBalance(address, 1000000);
console.log(`Historical balance: ${formatEther(historicalBalance)}`);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
balance_wei = w3.eth.get_balance(address)
balance = w3.from_wei(balance_wei, 'ether')

print(f'Balance: {balance}')

# Get balance at specific block
historical_balance = w3.eth.get_balance(address, block_identifier=1000000)
print(f'Historical balance: {w3.from_wei(historical_balance, "ether")}')
```

```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-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Convert to ether
    fbalance := new(big.Float).SetInt(balance)
    ethValue := new(big.Float).Quo(fbalance, big.NewFloat(1e18))

    fmt.Printf("Balance: %f\n", ethValue)
}
```

## Related Methods

- [`eth_getCode`](https://www.dwellir.com/docs/zora/eth_getCode) - Get contract bytecode
- [`eth_getTransactionCount`](https://www.dwellir.com/docs/zora/eth_getTransactionCount) - Get account nonce

---

## eth_getBlockByHash - Zora RPC Method

# eth_getBlockByHash - Zora RPC Method

Returns information about a block by hash on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getBlockByHash` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Block verification using deterministic hash lookup**: Retrieve block data by its unique, immutable hash on Zora
- **Chain reorganization handling**: Track blocks reliably by hash during reorgs on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators
- **Cross-chain bridge finality verification**: Confirm block existence by its canonical hash for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Deterministic queries when block number may change**: Ensure consistent results for applications that need stable references regardless of chain state

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte block hash
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByHash",
  "params": [
    "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
    false
  ],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used
- `transactions` (`Array, required`): Transaction objects or hashes

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x1",
    "hash": "<value>",
    "parentHash": "<value>",
    "timestamp": "0x1",
    "gasUsed": "0x1",
    "transactions": []
  }
}
```

## Common Use Cases

### 1. Verify a Specific Block from a Transaction's blockHash Field

When a transaction response includes `blockHash`, use `eth_getBlockByHash` to retrieve the full parent block. This cross-references the transaction's context and confirms which block it was included in on Zora.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function verifyBlockFromTx(txHash) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || !tx.blockHash) return null;

  const block = await provider.getBlock(tx.blockHash);
  console.log(`Transaction ${txHash} in block #${block.number}`);
  console.log(`Block hash: ${block.hash}`);
  console.log(`Block timestamp: ${new Date(block.timestamp * 1000).toISOString()}`);
  return block;
}

verifyBlockFromTx('0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea');
```

### 2. Cross-Reference Blocks During Chain Reorganization

During a chain reorganization, block numbers can shift but block hashes remain unique identifiers. Use `eth_getBlockByHash` to verify the canonical chain state and detect whether a previously observed block has been orphaned on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def verify_block_still_canonical(block_hash):
    block = w3.eth.get_block(block_hash)
    if block is None:
        print(f'Block {block_hash} has been pruned or orphaned')
        return False
    print(f'Block {block_hash} still canonical at height #{block.number}')
    return True

# Check a known block hash
verify_block_still_canonical('0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1')
```

### 3. Audit Block Data by Known Hash Reference

For compliance and audit workflows, store block hashes as permanent references. Re-querying `eth_getBlockByHash` with a stored hash guarantees you retrieve the exact same block data, even months later on Zora.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")

    knownHash := common.HexToHash("0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1")
    block, err := client.BlockByHash(context.Background(), knownHash)
    if err != nil || block == nil {
        log.Fatal("Block not found: may be pruned from node")
    }

    fmt.Printf("Audited block #%d\n", block.Number().Uint64())
    fmt.Printf("Hash: %s\n", block.Hash().Hex())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Best Practices

- **Hash-based lookups are more reliable during chain reorgs than number-based**: A block hash uniquely identifies one canonical block, while a block number may shift to a different block after a reorg
- **Store block hashes in your database for future verification**: Persisting the hash alongside related records enables deterministic re-querying for audits and data integrity checks
- **Handle `null` results gracefully**: Blocks can be pruned by the node, especially on non-archive endpoints; your application should treat a null response as a missing or unavailable block
- **For L2 optimistic rollups, verify the L1 anchor hash separately**: The hash on the L2 chain references a different block space than the L1 anchor; validate both independently for full finality confidence

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByHash",
    "params": [
      "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
      false
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const blockHash = '0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1';
const block = await provider.getBlock(blockHash);

console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

block_hash = '0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1'
block = w3.eth.get_block(block_hash)

print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    blockHash := common.HexToHash("0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1")
    block, err := client.BlockByHash(context.Background(), blockHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
}
```

## Related Methods

- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Get block by number
- [`eth_blockNumber`](https://www.dwellir.com/docs/zora/eth_blockNumber) - Get latest block number

---

## eth_getBlockByNumber - Zora RPC Method

# eth_getBlockByNumber - Zora RPC Method

Returns information about a block by block number on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getBlockByNumber` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Block explorers and analytics dashboards**: Display comprehensive block data and chain metrics for end-user interfaces on Zora
- **Transaction indexers processing block contents**: Extract and index every transaction within a block for data pipelines and search backends
- **Cross-chain bridges verifying block data**: Validate block headers and transaction proofs for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Timestamp-based logic**: Verify block age and enforce time-dependent contract logic on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators

## Request Parameters

- `blockNumber` (`QUANTITY|TAG, required`): Block number in hex, or "latest", "earliest", "pending", "safe", "finalized"
- `fullTransactions` (`Boolean, required`): If true, returns full transaction objects; if false, returns transaction hashes

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": ["latest", false],
  "id": 1
}
```

## Response Fields

- `number` (`QUANTITY, required`): Block number
- `hash` (`DATA, required`): 32-byte block hash
- `parentHash` (`DATA, required`): 32-byte parent block hash
- `timestamp` (`QUANTITY, required`): Unix timestamp
- `gasUsed` (`QUANTITY, required`): Total gas used by all transactions
- `gasLimit` (`QUANTITY, required`): Maximum gas allowed in block
- `transactions` (`Array, required`): Array of transaction objects or hashes
- `baseFeePerGas` (`QUANTITY, required`): Base fee per gas (EIP-1559)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "number": "0x5BAD55",
    "hash": "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
    "parentHash": "0x...",
    "timestamp": "0x64d8f6d0",
    "gasUsed": "0x1234",
    "gasLimit": "0x1c9c380",
    "transactions": [],
    "baseFeePerGas": "0x5f5e100"
  }
}
```

## Common Use Cases

### 1. Process All Transactions in the Latest Block

Fetch the latest block on Zora with full transaction objects, then iterate through each transaction to extract sender, receiver, value, and gas data. This pattern powers indexers, analytics dashboards, and event backfill pipelines.

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function processLatestBlock() {
  const block = await provider.getBlock('latest', true);

  if (!block) return;

  console.log(`Block #${block.number}: ${block.transactions.length} transactions`);

  for (const tx of block.prefetchedTransactions) {
    console.log(`  ${tx.hash}`);
    console.log(`    From: ${tx.from}  To: ${tx.to}`);
    console.log(`    Value: ${formatEther(tx.value)}  Gas: ${tx.gasLimit.toString()}`);
  }
}

processLatestBlock();
```

### 2. Monitor New Blocks with a Polling Loop

Poll `eth_getBlockByNumber` at regular intervals to detect new blocks as they are produced on Zora. This lightweight pattern is suitable for bots, watchers, and notification services that need near-real-time block awareness.

```python
from web3 import Web3
import time

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

last_block = w3.eth.block_number

print(f'Starting from block #{last_block}')

while True:
    current_block = w3.eth.block_number
    if current_block > last_block:
        for block_num in range(last_block + 1, current_block + 1):
            block = w3.eth.get_block(block_num)
            tx_count = len(block.transactions)
            print(f'New block #{block.number}: {tx_count} txns, '
                  f'gas used {block.gasUsed}')
        last_block = current_block
    time.sleep(2)
```

### 3. Verify Block Finality on L2 Chains

Layer 2 rollup chains on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators expose additional block tags that indicate settlement confidence. Use `safe` or `finalized` tags alongside the base `latest` tag for use cases requiring strong finality guarantees.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")

    // Latest block (may be unconfirmed on L2)
    latest, _ := client.BlockByNumber(context.Background(), nil)
    fmt.Printf("Latest block: %d (timestamp: %d)\n",
        latest.Number().Uint64(), latest.Time())

    // Finalized block (settled on L1 for rollups)
    finalized, _ := client.BlockByNumber(context.Background(),
        big.NewInt(int64(RPCLatestBlockNumber-32))) // placeholder: use rpc.FinalizedBlockNumber
    if finalized != nil {
        fmt.Printf("Finalized block: %d\n", finalized.Number().Uint64())
    }
}
```

## Best Practices

- **Cache block data by block number**: Blocks are immutable once finalized, so cache results indefinitely keyed by block number to eliminate redundant API calls
- **Use `latest` tag for most use cases; avoid `pending` for production**: The `pending` tag returns speculative data that may never be included in the canonical chain
- **For L2 chains, check chain-specific finality tags**: Tags like `safe` and `finalized` provide settlement guarantees specific to each rollup's proof mechanism
- **Combine with `eth_getBlockReceipts` for efficient receipt scanning**: When you need both block headers and transaction outcomes, use `eth_getBlockReceipts` alongside this method rather than fetching receipts individually

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get latest block
const block = await provider.getBlock('latest');
console.log('Block number:', block.number);
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transactions:', block.transactions.length);

// Get block with full transactions
const blockWithTxs = await provider.getBlock('latest', true);
for (const tx of blockWithTxs.prefetchedTransactions) {
  console.log('Transaction:', tx.hash);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Get latest block
block = w3.eth.get_block('latest')
print(f'Block number: {block.number}')
print(f'Timestamp: {block.timestamp}')
print(f'Transactions: {len(block.transactions)}')

# Get block with full transactions
block_full = w3.eth.get_block('latest', full_transactions=True)
for tx in block_full.transactions:
    print(f'Transaction: {tx.hash.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Get latest block
    block, err := client.BlockByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Block number: %d\n", block.Number().Uint64())
    fmt.Printf("Timestamp: %d\n", block.Time())
    fmt.Printf("Transactions: %d\n", len(block.Transactions()))
}
```

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/zora/eth_blockNumber) - Get latest block number
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zora/eth_getBlockByHash) - Get block by hash
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zora/eth_getTransactionByHash) - Get transaction details

---

## eth_getBlockReceipts - Zora RPC Method

# eth_getBlockReceipts - Zora RPC Method

Returns all transaction receipts for a block on Zora. This is more efficient than calling `eth_getTransactionReceipt` once per transaction when you already know the target block.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getBlockReceipts` is useful for NFT creators, digital artists, brands, and onchain media builders:

- **Indexer Backfills**: Pull every receipt in a block with one request instead of looping over transaction hashes
- **Event Collection**: Scan all logs emitted by a block when building analytics or data pipelines
- **Settlement Auditing**: Verify every transaction outcome in a target block for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Operational Debugging**: Compare receipt-level gas usage, status, and logs across multiple transactions at once

## Request Parameters

- `block` (`QUANTITY | TAG | DATA, required`): Block number, block tag such as latest, or 32-byte block hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockReceipts",
  "params": ["0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1"],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object> | null, required`): Array of receipt objects for the block, or null if the block is not found
- `transactionHash` (`DATA, required`): Transaction hash
- `status` (`QUANTITY, required`): 0x1 on success, 0x0 on failure
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in the block up to this transaction
- `logs` (`Array<Object>, required`): Logs emitted by the transaction
- `contractAddress` (`DATA | null, required`): Created contract address for deployment transactions
- `effectiveGasPrice` (`QUANTITY, required`): Effective gas price paid by the sender

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "transactionHash": "0x50b1857dce8dbe401e09610534de81655bc508c6765eb30ecefe24148c515c28",
      "transactionIndex": "0x0",
      "blockHash": "0x0ee8240b9393d92d059f1a87f4845ca5fd75f70aca8b1a97d98e1ea2560edf34",
      "blockNumber": "0xab47b2",
      "from": "0x0bd34b0a5be345c9bf7a147eb698e993511180cb",
      "to": "0xccc88a9d1b4ed6b0eaba998850414b24f1c315be",
      "gasUsed": "0x10b58",
      "cumulativeGasUsed": "0x10b58",
      "effectiveGasPrice": "0x9c7652400",
      "status": "0x0",
      "logs": [
        {
          "address": "0x20c0000000000000000000000000000000000000",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000b3b",
          "logIndex": "0x0",
          "removed": false
        }
      ]
    }
  ]
}
```

## Common Use Cases

### 1. Backfill Transaction Receipts for an Indexer

When bootstrapping an indexer for Zora, use `eth_getBlockReceipts` to backfill historical receipt data efficiently. One RPC call per block replaces dozens of individual `eth_getTransactionReceipt` calls.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function backfillReceipts(startBlock, endBlock) {
  const receipts = {};

  for (let i = startBlock; i <= endBlock; i++) {
    const hexBlock = '0x' + i.toString(16);
    const results = await provider.send('eth_getBlockReceipts', [hexBlock]);

    if (results) {
      for (const receipt of results) {
        receipts[receipt.transactionHash] = {
          block: i,
          status: receipt.status === '0x1' ? 'success' : 'failed',
          gasUsed: parseInt(receipt.gasUsed, 16),
          logCount: receipt.logs.length,
        };
      }
    }
    console.log(`Backfilled block ${i}: ${results ? results.length : 0} receipts`);
  }

  return receipts;
}

backfillReceipts(10000000, 10000050);
```

### 2. Audit Gas Usage Across All Transactions in a Range

Compute total gas consumption and identify high-gas transactions within a target block range on Zora. This is useful for gas cost analysis and identifying optimization targets in smart contract usage.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def audit_gas_usage(block_identifier):
    response = w3.provider.make_request(
        'eth_getBlockReceipts', [block_identifier]
    )

    receipts = response.get('result')
    if not receipts:
        print(f'No receipts found for block {block_identifier}')
        return

    total_gas = 0
    for receipt in receipts:
        gas = int(receipt['gasUsed'], 16)
        total_gas += gas
        if gas > 500_000:
            print(f'High gas tx: {receipt["transactionHash"]} used {gas:,} gas')

    print(f'Block {block_identifier}: {len(receipts)} txs, '
          f'total gas {total_gas:,}')

audit_gas_usage('0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1')
```

### 3. Extract Contract Creation Events from Deployment Blocks

When monitoring contract deployments on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators, use `eth_getBlockReceipts` to scan for receipts where `contractAddress` is non-null. This identifies all new contract deployments within a block in a single call.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, _ := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")

    var receipts []map[string]interface{}
    err := client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range receipts {
        contractAddr, ok := r["contractAddress"]
        if ok && contractAddr != nil {
            fmt.Printf("Contract deployed: %s\n", contractAddr)
            fmt.Printf("  Creator: %s\n", r["from"])
            fmt.Printf("  Tx hash: %s\n", r["transactionHash"])
        }
    }
}
```

## Best Practices

- **Use block hash instead of block number for deterministic results**: Hash-based lookups guarantee you are querying the exact block intended, even if chain reorganizations shift block numbers
- **Paginate large receipt arrays client-side**: Blocks with thousands of transactions return large payloads; paginate processing to avoid memory pressure in your application
- **Cache individual receipt data per transaction hash**: Receipts are immutable once a block is finalized, so cache them indefinitely for repeated lookups
- **For historical blocks, archive nodes may return more complete receipt data**: Full nodes may prune older state; archive nodes retain complete historical receipt information

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBlockReceipts",
    "params": ["0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const receipts = await provider.send('eth_getBlockReceipts', [
  '0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1',
]);

console.log('Receipt count:', receipts.length);
console.log('First tx status:', receipts[0]?.status);
console.log('First tx logs:', receipts[0]?.logs.length ?? 0);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

response = w3.provider.make_request(
    'eth_getBlockReceipts',
    ['0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1'],
)

receipts = response['result']
print(f'Receipt count: {len(receipts)}')
print(f'First tx status: {receipts[0][\"status\"]}')
print(f'First tx logs: {len(receipts[0][\"logs\"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var receipts []map[string]any
    err = client.CallContext(
        context.Background(),
        &receipts,
        "eth_getBlockReceipts",
        "0x3d67b126a801e8243045bc91ec5dcc4bedec3ce21029575e99b6ecd0aea28dc1",
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Receipt count: %d\n", len(receipts))
    if len(receipts) > 0 {
        fmt.Printf("First tx status: %v\n", receipts[0]["status"])
    }
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zora/eth_getTransactionReceipt) - Retrieve a single transaction receipt
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zora/eth_getBlockByHash) - Retrieve the block object itself
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Retrieve a block by number or tag

---

## eth_getCode - Zora RPC Method

# eth_getCode - Zora RPC Method

Returns the bytecode at a given address on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getCode` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Contract Verification** -- Verify that the bytecode deployed at an address matches the expected source code compilation output on Zora
- **EOA vs Contract Detection** -- Determine whether an address is an externally owned account (returns `0x`) or a deployed smart contract (returns bytecode)
- **Proxy Pattern Detection** -- Check if a proxy contract has been initialized by examining whether its implementation slot contains code
- **Security Auditing** -- Validate contract deployments before interacting with them on low-cost NFT minting, onchain media monetization, and creator-owned token economies

## Common Use Cases

### 1. Detect Contract vs EOA

Determine if an address is a smart contract or a regular wallet on Zora:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x' && code !== '0x0';
}

async function classifyAddress(address) {
  if (await isContract(address)) {
    const balance = await provider.getBalance(address);
    console.log('Contract at', address, '- balance:', balance.toString());
    return 'contract';
  }
  console.log('EOA at', address);
  return 'eoa';
}
```

### 2. Verify Proxy Implementation Initialization

Check whether a proxy contract has been initialized with an implementation on Zora:

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function checkProxyInitialized(proxyAddress) {
  // EIP-1967 implementation slot
  const IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
  
  const slotValue = await provider.getStorage(proxyAddress, IMPL_SLOT);
  const implAddress = '0x' + slotValue.slice(26);
  
  const implCode = await provider.getCode(implAddress);
  const hasCode = implCode !== '0x' && implCode !== '0x0';
  
  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress} (has code: ${hasCode})`);
  
  return hasCode;
}
```

### 3. Batch Contract Detection

Scan multiple addresses to classify them efficiently:

```javascript
async function scanAddresses(provider, addresses) {
  const results = [];
  
  for (const address of addresses) {
    try {
      const code = await provider.getCode(address);
      const type = (code === '0x' || code === '0x0') ? 'EOA' : 'Contract';
      results.push({ address, type, bytecodeSize: code.length });
    } catch (error) {
      results.push({ address, type: 'Error', error: error.message });
    }
  }
  
  const summary = {
    total: results.length,
    contracts: results.filter(r => r.type === 'Contract').length,
    eoas: results.filter(r => r.type === 'EOA').length,
    errors: results.filter(r => r.type === 'Error').length
  };
  
  console.log('Scan results:', summary);
  return { results, summary };
}
```

## Best Practices

- Check both `0x` and `0x0` return values -- different client implementations return one or the other for EOAs
- Use historical block numbers with `eth_getCode` to verify contract state at a specific point in time
- For proxy pattern detection, combine `eth_getCode` with `eth_getStorageAt` to fully verify initialization
- Cache bytecode by address, as deployed contract code is immutable
- The return value length is roughly 2x the deployment bytecode size (hex encoding doubles the byte count)

## Request Parameters

- `address` (`DATA, required`): 20-byte address
- `blockParameter` (`QUANTITY|TAG, required`): Block number or tag

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): Contract bytecode or 0x if EOA

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "<value>"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getCode",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const address = '0x4200000000000000000000000000000000000006';
const code = await provider.getCode(address);

if (code === '0x') {
  console.log('Address is an EOA (externally owned account)');
} else {
  console.log('Address is a contract');
  console.log('Bytecode length:', code.length);
}

// Check if address is a contract
async function isContract(address) {
  const code = await provider.getCode(address);
  return code !== '0x';
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

address = '0x4200000000000000000000000000000000000006'
code = w3.eth.get_code(address)

if code == b'':
    print('Address is an EOA')
else:
    print('Address is a contract')
    print(f'Bytecode length: {len(code.hex())}')

# Check if address is a contract
def is_contract(address):
    code = w3.eth.get_code(address)
    return code != b''
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    code, err := client.CodeAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }

    if len(code) == 0 {
        fmt.Println("Address is an EOA")
    } else {
        fmt.Printf("Contract bytecode length: %d\n", len(code))
    }
}
```

## Related Methods

- [`eth_getBalance`](https://www.dwellir.com/docs/zora/eth_getBalance) - Get account balance
- [`eth_getStorageAt`](https://www.dwellir.com/docs/zora/eth_getStorageAt) - Get contract storage

---

## eth_getFilterChanges - Zora RPC Method

# eth_getFilterChanges - Zora RPC Method

Polls a filter on Zora for changes since the last poll. Log filters return log objects. Block filters return block hashes. Pending transaction filters return transaction hashes.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getFilterChanges` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Event Streaming** - Incrementally consume new contract events without re-fetching the entire log history on Zora
- **Real-Time Monitoring** - Track contract activity, token transfers, or governance votes for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Efficient Log Indexing** - Process only new events since your last poll, minimizing bandwidth and compute overhead
- **Block & Transaction Tracking** - When used with block or pending-transaction filters, detect new blocks or mempool activity in real time

## Best Practices

- Poll filters at most every 1-5 seconds; excessive polling wastes bandwidth and may trigger rate limiting
- Always call `eth_uninstallFilter` when monitoring is complete to release server-side resources
- Handle null or empty array returns gracefully as they indicate no new results since the last poll
- Use WebSocket subscriptions (`eth_subscribe`) instead of polling for real-time production applications

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterChanges",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes of new blocks
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes of pending transactions

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456...",
      "logIndex": "0x0",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getFilterChanges",
    "params": ["0x1a"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a log filter first
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Poll for new events
async function pollFilter(filterId, interval = 2000) {
  while (true) {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      for (const log of changes) {
        console.log('New event in block:', parseInt(log.blockNumber, 16));
        console.log('  Contract:', log.address);
        console.log('  Data:', log.data);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollFilter(filterId);
```

```python
import requests
import time

RPC_URL = 'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a log filter
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Poll for changes
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    logs = changes.get('result', [])
    if logs:
        for log in logs:
            block = int(log['blockNumber'], 16)
            print(f'New event in block {block}: {log["address"]}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a log filter
    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    // Using SubscribeFilterLogs for real-time events
    logs := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
    if err != nil {
        // Fallback: use polling with FilterLogs
        ticker := time.NewTicker(2 * time.Second)
        currentBlock, _ := client.BlockNumber(context.Background())

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                results, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range results {
                        fmt.Printf("Log in block %d from %s\n", l.BlockNumber, l.Address.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logs:
            fmt.Printf("Log in block %d from %s\n", vLog.BlockNumber, vLog.Address.Hex())
        }
    }
}
```

## Common Use Cases

### 1. Real-Time Token Transfer Monitor

Stream ERC-20 transfer events on Zora:

```javascript
async function monitorTransfers(provider, tokenAddress) {
  // Transfer event topic: keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring transfers on ${tokenAddress}...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);
        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - recreating...');
        // Filters expire after ~5 minutes of inactivity on most nodes
      }
    }
  }, 3000);
}
```

### 2. Multi-Contract Event Aggregator

Monitor events across multiple contracts simultaneously:

```javascript
async function aggregateEvents(provider, contracts) {
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: contracts  // Array of contract addresses
  }]);

  const eventBuffer = [];
  let pollCount = 0;

  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    pollCount++;

    if (changes.length > 0) {
      eventBuffer.push(...changes);
      console.log(`Poll #${pollCount}: ${changes.length} new events (total: ${eventBuffer.length})`);

      // Process in batches
      if (eventBuffer.length >= 50) {
        await processBatch(eventBuffer.splice(0, 50));
      }
    }
  }, 2000);

  return { filterId, stop: () => clearInterval(interval) };
}
```

### 3. Block-Aware Event Processor with Reorg Handling

Detect chain reorganizations by checking the `removed` flag:

```javascript
async function safeEventProcessor(provider, filterParams) {
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const processedEvents = new Map();

  setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of changes) {
      const eventKey = `${log.transactionHash}-${log.logIndex}`;

      if (log.removed) {
        // Chain reorganization - undo previously processed event
        console.warn(`Reorg detected: removing event ${eventKey}`);
        processedEvents.delete(eventKey);
        await rollbackEvent(log);
      } else {
        processedEvents.set(eventKey, log);
        await processEvent(log);
      }
    }
  }, 2000);
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zora/eth_newFilter) - Create a log/event filter to poll with this method
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zora/eth_newBlockFilter) - Create a block filter for new block notifications
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zora/eth_getFilterLogs) - Get all logs matching a filter (full history, not incremental)
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zora/eth_uninstallFilter) - Remove a filter when no longer needed
- [`eth_getLogs`](https://www.dwellir.com/docs/zora/eth_getLogs) - Query logs directly without creating a filter

---

## eth_getFilterLogs - Zora RPC Method

# eth_getFilterLogs - Zora RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on Zora. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getFilterLogs` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on Zora
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x4200000000000000000000000000000000000006"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x4200000000000000000000000000000000000006'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zora/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zora/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/zora/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zora/eth_uninstallFilter) - Remove a filter when no longer needed

---

## eth_getLogs - Zora RPC Method

# eth_getLogs - Zora RPC Method

Returns an array of all logs matching a given filter object on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for NFT creators, digital artists, brands, and onchain media builders:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Zora for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Zora
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x4200000000000000000000000000000000000006';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x4200000000000000000000000000000000000006';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Zora.

```javascript
const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Zora enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Zora, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Contract } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x4200000000000000000000000000000000000006',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x4200000000000000000000000000000000000006',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zora/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zora/eth_getFilterChanges) - Poll filter for new logs

---

## eth_getStorageAt - Zora RPC Method

# eth_getStorageAt - Zora RPC Method

Returns the value from a storage position at a given address on Zora. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getStorageAt` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **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 low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **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": [
    "0x4200000000000000000000000000000000000006",
    "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-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getStorageAt",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getStorageAt',
    params: ['0x4200000000000000000000000000000000000006', '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-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

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-zora-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 = '0x4200000000000000000000000000000000000006'
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-zora-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-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")
    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 Zora:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-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-zora-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 = '0x4200000000000000000000000000000000000006';
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 Zora:`);
  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/zora/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/zora/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/zora/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Get block details for historical storage queries

---

## eth_getTransactionByHash - Zora RPC Method

# eth_getTransactionByHash - Zora RPC Method

Returns the information about a transaction by transaction hash on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getTransactionByHash` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Track pending and confirmed transaction status**: Monitor the full lifecycle of a transaction from submission through finalization on Zora
- **Verify transaction parameters**: Confirm the value, gas, and input data match your intent for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Wallet transaction history display**: Show detailed transaction records with sender, receiver, value, and status for end users
- **Debug failed transactions**: Inspect raw transaction data to diagnose reverted calls and unexpected behavior on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionByHash",
  "params": ["0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea"],
  "id": 1
}
```

## Response Fields

- `hash` (`DATA, required`): Transaction hash
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasPrice` (`QUANTITY, required`): Gas price in wei
- `input` (`DATA, required`): Transaction input data
- `nonce` (`QUANTITY, required`): Sender's nonce
- `blockHash` (`DATA, required`): Block hash (null if pending)
- `blockNumber` (`QUANTITY, required`): Block number (null if pending)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "hash": "<value>",
    "from": "<value>",
    "to": "<value>",
    "value": "0x1",
    "gas": "0x1",
    "gasPrice": "0x1",
    "input": "<value>",
    "nonce": "0x1",
    "blockHash": "<value>",
    "blockNumber": "0x1"
  }
}
```

## Common Use Cases

### 1. Wait for Transaction Confirmation with Polling

Poll `eth_getTransactionByHash` until the transaction's `blockNumber` becomes non-null, indicating it has been mined on Zora. This is the standard pattern for tracking transaction finality.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function waitForConfirmation(txHash, interval = 2000) {
  while (true) {
    const tx = await provider.getTransaction(txHash);

    if (tx && tx.blockNumber) {
      console.log(`Transaction confirmed in block #${tx.blockNumber}`);
      return tx;
    }

    console.log('Transaction pending, waiting...');
    await new Promise(r => setTimeout(r, interval));
  }
}

waitForConfirmation('0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea');
```

### 2. Display Transaction Details in a Wallet UI

Fetch and format transaction data for display in a wallet or explorer on Zora. Extract the key fields: sender, recipient, value, gas, and confirmation status.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def get_transaction_details(tx_hash):
    tx = w3.eth.get_transaction(tx_hash)

    if not tx:
        return {'status': 'not found'}

    return {
        'hash': tx['hash'].hex(),
        'from': tx['from'],
        'to': tx['to'],
        'value_ether': w3.from_wei(tx['value'], 'ether'),
        'gas': tx['gas'],
        'gas_price_gwei': w3.from_wei(tx['gasPrice'], 'gwei'),
        'block': tx.get('blockNumber'),
        'confirmed': tx.get('blockNumber') is not None,
    }

details = get_transaction_details('0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea')
for key, value in details.items():
    print(f'{key}: {value}')
```

### 3. Decode Transaction Input Data for Contract Interaction Analysis

When a transaction's `input` field contains encoded function calls, decode it using a contract ABI to understand what action was performed on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators.

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea")
    tx, isPending, _ := client.TransactionByHash(context.Background(), txHash)

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("From: %s\n", tx.From().Hex())
    fmt.Printf("Value: %s wei\n", tx.Value().String())
    fmt.Printf("Gas limit: %d\n", tx.Gas())

    if len(tx.Data()) > 0 {
        // First 4 bytes are the function selector
        selector := tx.Data()[:4]
        fmt.Printf("Function selector: 0x%x\n", selector)
        fmt.Printf("Input data length: %d bytes\n", len(tx.Data()))
    }
}
```

## Best Practices

- **Check if `blockNumber` is null to detect pending transactions**: A null `blockNumber` indicates the transaction has been submitted but not yet mined; use this to drive polling or loading states in your UI
- **For mined transactions, cross-reference with receipt for confirmation count**: Once a block number is available, use `eth_getTransactionReceipt` to get the final status, gas used, and emitted logs
- **Cache confirmed transaction data indefinitely**: Transaction data is immutable once mined; cache it permanently to avoid redundant RPC calls for historical lookups
- **Use `eth_getTransactionReceipt` for post-confirmation data**: After a transaction is confirmed, call `eth_getTransactionReceipt` to get gas used, logs, status code, and effective gas price

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionByHash",
    "params": ["0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, formatEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea';
const tx = await provider.getTransaction(txHash);

if (tx) {
  console.log('From:', tx.from);
  console.log('To:', tx.to);
  console.log('Value:', formatEther(tx.value));
  console.log('Block:', tx.blockNumber);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea'
tx = w3.eth.get_transaction(tx_hash)

if tx:
    print(f'From: {tx["from"]}')
    print(f'To: {tx["to"]}')
    print(f'Value: {w3.from_wei(tx["value"], "ether")}')
    print(f'Block: {tx["blockNumber"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea")
    tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Pending: %v\n", isPending)
    fmt.Printf("Value: %s\n", tx.Value().String())
}
```

## Related Methods

- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zora/eth_getTransactionReceipt) - Get transaction receipt
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Send transaction

---

## eth_getTransactionCount - Zora RPC Method

# eth_getTransactionCount - Zora RPC Method

Returns the number of transactions sent from an address on Zora, commonly known as the **nonce**. The nonce is required for every outbound transaction to ensure correct ordering and prevent replay attacks.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getTransactionCount` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Transaction Signing** - Get the correct nonce before building and signing a new transaction on Zora
- **Nonce Gap Detection** - Compare `latest` and `pending` nonces to identify stuck or dropped transactions in the mempool
- **Account Activity Analysis** - Track the total number of outgoing transactions from any address on low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Batch Transaction Sequencing** - Assign sequential nonces when submitting multiple transactions from the same address

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address to query the transaction count for
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest (confirmed nonce), pending (includes mempool txs), earliest

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionCount",
  "params": [
    "0x4200000000000000000000000000000000000006",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of transactions sent from the address

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a"
}
```

## 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-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionCount",
    "params": [
      "0x4200000000000000000000000000000000000006",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_getTransactionCount',
    params: ['0x4200000000000000000000000000000000000006', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
const nonce = parseInt(result, 16);
console.log('Zora nonce:', nonce);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0x4200000000000000000000000000000000000006';

const nonce = await provider.getTransactionCount(address);
console.log('Confirmed nonce:', nonce);

// Get pending nonce for new transaction
const pendingNonce = await provider.getTransactionCount(address, 'pending');
console.log('Next nonce:', pendingNonce);
```

```python
import requests

def get_transaction_count(address, block='latest'):
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getTransactionCount',
            'params': [address, block],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

address = '0x4200000000000000000000000000000000000006'
nonce = get_transaction_count(address)
print(f'Zora nonce: {nonce}')

pending_nonce = get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending_nonce}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
nonce = w3.eth.get_transaction_count(address)
print(f'Nonce: {nonce}')

pending = w3.eth.get_transaction_count(address, 'pending')
print(f'Pending nonce: {pending}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0x4200000000000000000000000000000000000006")

    // Get confirmed nonce
    nonce, err := client.NonceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Zora nonce: %d\n", nonce)

    // Get pending nonce for new transaction
    pendingNonce, err := client.PendingNonceAt(context.Background(), address)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Pending nonce: %d\n", pendingNonce)
}
```

## Common Use Cases

### 1. Safe Transaction Sender with Nonce Management

Build a transaction sender that handles nonces correctly on Zora:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

class TransactionSender {
  constructor(privateKey) {
    this.wallet = new Wallet(privateKey, provider);
    this.localNonce = null;
  }

  async getNextNonce() {
    // Get the pending nonce from the network
    const pendingNonce = await provider.getTransactionCount(
      this.wallet.address, 'pending'
    );

    // Use whichever is higher: local tracker or network pending
    if (this.localNonce === null || pendingNonce > this.localNonce) {
      this.localNonce = pendingNonce;
    }

    const nonce = this.localNonce;
    this.localNonce++;
    return nonce;
  }

  async sendTransaction(to, valueEth) {
    const nonce = await this.getNextNonce();

    const tx = await this.wallet.sendTransaction({
      to,
      value: parseEther(valueEth),
      nonce
    });

    console.log(`Sent tx ${tx.hash} with nonce ${nonce}`);
    return tx;
  }

  // Reset local nonce tracker (e.g., after errors)
  resetNonce() {
    this.localNonce = null;
  }
}
```

### 2. Stuck Transaction Detector

Detect and report stuck transactions by comparing nonces:

```javascript
async function detectStuckTransactions(provider, address) {
  const confirmedNonce = await provider.getTransactionCount(address, 'latest');
  const pendingNonce = await provider.getTransactionCount(address, 'pending');

  const pendingCount = pendingNonce - confirmedNonce;

  if (pendingCount === 0) {
    console.log('No pending transactions');
    return { status: 'clear', pendingCount: 0 };
  }

  console.log(`${pendingCount} pending transaction(s) detected`);
  console.log(`Confirmed nonce: ${confirmedNonce}`);
  console.log(`Pending nonce: ${pendingNonce}`);
  console.log(`Stuck nonces: ${confirmedNonce} to ${pendingNonce - 1}`);

  return {
    status: 'stuck',
    pendingCount,
    confirmedNonce,
    pendingNonce,
    stuckNonces: Array.from(
      { length: pendingCount },
      (_, i) => confirmedNonce + i
    )
  };
}

// Usage
const result = await detectStuckTransactions(provider, '0x4200000000000000000000000000000000000006');
if (result.status === 'stuck') {
  console.log('Consider replacing transactions at nonces:', result.stuckNonces);
}
```

### 3. Batch Transaction Submitter

Submit multiple transactions in sequence with correct nonce ordering:

```javascript
async function sendBatchTransactions(wallet, transactions) {
  const startNonce = await provider.getTransactionCount(
    wallet.address, 'pending'
  );

  console.log(`Sending ${transactions.length} transactions starting at nonce ${startNonce}`);

  const receipts = [];
  for (let i = 0; i < transactions.length; i++) {
    const nonce = startNonce + i;
    const tx = await wallet.sendTransaction({
      ...transactions[i],
      nonce
    });

    console.log(`Tx ${i + 1}/${transactions.length} sent: ${tx.hash} (nonce: ${nonce})`);
    receipts.push(tx);
  }

  // Wait for all to confirm
  const confirmed = await Promise.all(
    receipts.map(tx => tx.wait())
  );

  console.log(`All ${confirmed.length} transactions confirmed`);
  return confirmed;
}

// Usage
const transactions = [
  { to: '0xRecipient1...', value: parseEther('0.1') },
  { to: '0xRecipient2...', value: parseEther('0.2') },
  { to: '0xRecipient3...', value: parseEther('0.05') }
];

await sendBatchTransactions(wallet, transactions);
```

## Best Practices

- Always use `pending` block tag when fetching the nonce for a new transaction to avoid nonce collisions
- Track nonces locally with a monotonic counter that syncs with the pending nonce from the network on reset
- If `pending` nonce equals `latest` nonce, no stuck transactions exist -- the account is clean
- For high-throughput applications (multiple transactions per second), implement a local nonce manager with retry logic
- The nonce starts at 0 for new accounts and increments by 1 for each confirmed outbound transaction

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Send a signed transaction to the network
- [`eth_getBalance`](https://www.dwellir.com/docs/zora/eth_getBalance) - Get the ETH balance of an address
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zora/eth_getTransactionByHash) - Get transaction details by hash
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zora/eth_getTransactionReceipt) - Get the receipt of a confirmed transaction

---

## eth_getTransactionReceipt - Zora RPC Method

# eth_getTransactionReceipt - Zora RPC Method

Returns the receipt of a transaction by transaction hash on Zora. Receipt is only available for mined transactions.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_getTransactionReceipt` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Transaction confirmation with success/failure status**: Verify that a transaction has been mined on Zora and determine whether it succeeded or reverted
- **Gas usage analysis**: Compare actual gas consumed against pre-transaction estimates for low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Event log parsing from emitted events**: Extract and decode contract events for indexing, analytics, and notification systems
- **Contract deployment detection**: Identify newly deployed contracts on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators by checking the `contractAddress` field

## Request Parameters

- `transactionHash` (`DATA, required`): 32-byte transaction hash

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": ["0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea"],
  "id": 1
}
```

## Response Fields

- `status` (`QUANTITY, required`): 1 (success) or 0 (failure)
- `transactionHash` (`DATA, required`): Transaction hash
- `blockHash` (`DATA, required`): Block hash
- `blockNumber` (`QUANTITY, required`): Block number
- `gasUsed` (`QUANTITY, required`): Gas used by this transaction
- `cumulativeGasUsed` (`QUANTITY, required`): Total gas used in block up to this tx
- `logs` (`Array, required`): Array of log objects
- `contractAddress` (`DATA, required`): Created contract address (if deployment)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "0x1",
    "transactionHash": "<value>",
    "blockHash": "<value>",
    "blockNumber": "0x1",
    "gasUsed": "0x1",
    "cumulativeGasUsed": "0x1",
    "logs": [],
    "contractAddress": "<value>"
  }
}
```

## Common Use Cases

### 1. Confirm Transaction Success and Parse Emitted Events

Poll `eth_getTransactionReceipt` after submitting a transaction to confirm it was mined successfully on Zora. Once available, iterate through the `logs` array to decode and process events emitted by the transaction.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function confirmAndParse(txHash) {
  let receipt = null;

  while (!receipt) {
    receipt = await provider.getTransactionReceipt(txHash);
    if (!receipt) {
      console.log('Waiting for confirmation...');
      await new Promise(r => setTimeout(r, 2000));
    }
  }

  const status = receipt.status === 1 ? 'Success' : 'Failed';
  console.log(`Transaction ${status} in block #${receipt.blockNumber}`);
  console.log(`Gas used: ${receipt.gasUsed.toString()}`);
  console.log(`Events emitted: ${receipt.logs.length}`);

  for (const log of receipt.logs) {
    console.log(`  Event from ${log.address} with topics:`, log.topics);
  }

  return receipt;
}

confirmAndParse('0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea');
```

### 2. Detect Contract Deployments by Checking contractAddress

When monitoring the chain for new contract deployments on Zora, check the `contractAddress` field in transaction receipts. A non-null value indicates a contract creation transaction.

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def detect_deployment(tx_hash):
    receipt = w3.eth.get_transaction_receipt(tx_hash)

    if not receipt:
        print(f'Transaction {tx_hash} not yet mined')
        return None

    if receipt['contractAddress']:
        print(f'Contract deployed at: {receipt["contractAddress"]}')
        print(f'Deployer: {receipt["from"]}')
        print(f'Gas used: {receipt["gasUsed"]}')
        return receipt['contractAddress']
    else:
        print(f'Transaction {tx_hash} is not a contract deployment')
        return None

detect_deployment('0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea')
```

### 3. Compute Effective Gas Price Paid by the Sender

Use the `effectiveGasPrice` field from the receipt (available on EIP-1559 chains) to calculate the actual cost of a transaction on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators. Compare this against the gas price from the transaction object for fee analysis.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, _ := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")

    txHash := common.HexToHash("0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea")
    receipt, _ := client.TransactionReceipt(context.Background(), txHash)

    if receipt == nil {
        log.Fatal("Transaction not yet mined")
    }

    status := "Success"
    if receipt.Status == 0 {
        status = "Failed"
    }

    fmt.Printf("Status: %s\n", status)
    fmt.Printf("Block: %d\n", receipt.BlockNumber.Uint64())
    fmt.Printf("Gas used: %d\n", receipt.GasUsed)

    // Calculate total cost: gasUsed * effectiveGasPrice
    totalCost := new(big.Int).Mul(
        big.NewInt(int64(receipt.GasUsed)),
        receipt.EffectiveGasPrice,
    )
    fmt.Printf("Total cost: %s wei\n", totalCost.String())

    if receipt.ContractAddress != (common.Address{}) {
        fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
    }
}
```

## Best Practices

- **Receipt is only available after mining; poll until non-null**: A `null` response means the transaction is pending or not found; implement a polling loop with exponential backoff to wait for confirmation
- **Check the `status` field**: `0x1` indicates a successful execution; `0x0` means the transaction reverted and may have consumed all provided gas
- **Parse the `logs` array for events using known topic hashes**: Each log entry contains up to 4 indexed topics and a data field; use ABI definitions to decode them into readable event parameters
- **For frontrunning detection, compare effective gas price across similar transactions**: Monitoring the `effectiveGasPrice` across transactions in a block can reveal priority gas auction dynamics on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators
- **`contractAddress` is non-null only for contract deployment transactions**: Use this field to distinguish regular transfers from contract create operations

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getTransactionReceipt",
    "params": ["0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const txHash = '0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea';
const receipt = await provider.getTransactionReceipt(txHash);

if (receipt) {
  console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
  console.log('Gas Used:', receipt.gasUsed.toString());
  console.log('Block:', receipt.blockNumber);
  console.log('Logs:', receipt.logs.length);

  // Parse specific events
  for (const log of receipt.logs) {
    console.log('Event from:', log.address);
  }
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

tx_hash = '0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea'
receipt = w3.eth.get_transaction_receipt(tx_hash)

if receipt:
    status = 'Success' if receipt['status'] == 1 else 'Failed'
    print(f'Status: {status}')
    print(f'Gas Used: {receipt["gasUsed"]}')
    print(f'Block: {receipt["blockNumber"]}')
    print(f'Logs: {len(receipt["logs"])}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    txHash := common.HexToHash("0x8035ffab84a5d72f051f78cff81e04d8b6b80cfbafc39a7c5d00d4d9230c87ea")
    receipt, err := client.TransactionReceipt(context.Background(), txHash)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Status: %d\n", receipt.Status)
    fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
    fmt.Printf("Logs: %d\n", len(receipt.Logs))
}
```

## Related Methods

- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zora/eth_getTransactionByHash) - Get transaction details
- [`eth_getLogs`](https://www.dwellir.com/docs/zora/eth_getLogs) - Query logs by filter

---

## eth_hashrate - Zora RPC Method

# eth_hashrate - Zora RPC Method

Returns the legacy `eth_hashrate` compatibility value on Zora. Depending on the client behind the endpoint, this call may return a hex quantity like `0x0` or a method-not-found style error.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

> **Note:** Treat `eth_hashrate` as a node-local mining metric and compatibility value. Public endpoints often report `0x0` or reject the method entirely, so it is not a reliable chain-health or consensus signal.

## When to Use This Method

`eth_hashrate` is relevant for NFT creators, digital artists, brands, and onchain media builders:

- **Node Diagnostics** - Check whether the connected client reports a legacy hashrate metric
- **Client Capability Checks** - Distinguish between `0x0`, unsupported-method, and method-not-found responses
- **Dashboard Integration** - Display the metric alongside other node status data when it is available

## Best Practices

- Returns `0x0` on proof-of-stake chains (post-Merge) and most modern deployments
- Not relevant for most production environments; treat as informational only
- Do not rely on this method for chain health or consensus signals
- Use eth\_syncing or eth\_blockNumber for reliable node status monitoring

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_hashrate",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the reported compatibility value when the client exposes the method

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_hashrate",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_hashrate',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_hashrate unsupported:', payload.error.message);
} else {
  console.log('Zora hashrate:', parseInt(payload.result, 16), 'H/s');
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const hashrate = await provider.send('eth_hashrate', []);
  console.log('Zora hashrate:', parseInt(hashrate, 16), 'H/s');
} catch (error) {
  console.log('eth_hashrate unsupported:', error.message);
}
```

```python
import requests

def get_hashrate():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_hashrate',
            'params': [],
            'id': 1
        }
    )
    payload = response.json()
    if 'error' in payload:
        raise RuntimeError(payload['error']['message'])
    return int(payload['result'], 16)

hashrate = get_hashrate()
print(f'Zora hashrate: {hashrate} H/s')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Zora hashrate: {w3.eth.hashrate} H/s')
except Exception as exc:
    print(f'eth_hashrate unsupported: {exc}')
```

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_hashrate")
    if err != nil {
        log.Println("eth_hashrate unsupported:", err)
        return
    }

    fmt.Printf("Zora hashrate: %s\n", result)
}
```

## Common Use Cases

### 1. Compatibility-Aware Status Dashboard

Display the reported compatibility value alongside other client status signals without assuming the method is always available:

```javascript
async function getMiningStats(provider) {
  const blockNumber = await provider.getBlockNumber();
  let hashrate = null;
  let supported = true;

  try {
    hashrate = await provider.send('eth_hashrate', []);
  } catch (error) {
    supported = false;
  }

  return {
    supported,
    hashrate: hashrate ? parseInt(hashrate, 16) : null,
    currentBlock: blockNumber
  };
}
```

### 2. Capability Check

Check whether the connected client reports `eth_hashrate` at all:

```javascript
async function getHashrateStatus(provider) {
  try {
    const hashrate = await provider.send('eth_hashrate', []);
    return { supported: true, raw: hashrate, isZero: hashrate === '0x0' };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

console.log(await getHashrateStatus(provider));
```

zing - retry after delay |
\| -32601 | Method not found | Node client may not support this method |
\| -32005 | Rate limit exceeded | Reduce polling frequency |

## Related Methods

- [`eth_mining`](https://www.dwellir.com/docs/zora/eth_mining) - Check if the node is actively mining
- [`eth_coinbase`](https://www.dwellir.com/docs/zora/eth_coinbase) - Get the mining/coinbase address
- [`eth_blockNumber`](https://www.dwellir.com/docs/zora/eth_blockNumber) - Get the current block height

---

## eth_maxPriorityFeePerGas - Zora RPC Method

# eth_maxPriorityFeePerGas - Zora RPC Method

Returns the current suggested priority fee (tip) per gas in wei on Zora. This is the amount paid directly to validators to incentivize faster transaction inclusion in EIP-1559 compatible blocks.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_maxPriorityFeePerGas` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **EIP-1559 Transaction Building** - Get the recommended tip to include in `maxPriorityFeePerGas` when constructing type-2 transactions on Zora
- **Fee Optimization** - Balance transaction speed against cost by adjusting the priority fee relative to the suggested value
- **Time-Sensitive Transactions** - Increase the tip above the suggested value for DEX swaps, liquidations, or other latency-sensitive operations on low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **Gas Price Estimation** - Combine with `baseFeePerGas` from the latest block to calculate the total `maxFeePerGas` for accurate fee estimation

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the suggested priority fee per gas in wei

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x3B9ACA00"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method eth_maxPriorityFeePerGas does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_maxPriorityFeePerGas",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_maxPriorityFeePerGas',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const priorityFeeWei = BigInt(result);
const priorityFeeGwei = Number(priorityFeeWei) / 1e9;
console.log('Zora priority fee:', priorityFeeGwei, 'Gwei');

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const feeData = await provider.getFeeData();
console.log('Max Priority Fee:', formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Max Fee Per Gas:', formatUnits(feeData.maxFeePerGas, 'gwei'), 'Gwei');
```

```python
import requests

def get_max_priority_fee():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_maxPriorityFeePerGas',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

priority_fee_wei = get_max_priority_fee()
priority_fee_gwei = priority_fee_wei / 1e9
print(f'Zora priority fee: {priority_fee_gwei} Gwei')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
priority_fee = w3.eth.max_priority_fee
print(f'Max Priority Fee: {w3.from_wei(priority_fee, "gwei")} Gwei')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    tip, err := client.SuggestGasTipCap(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).Quo(new(big.Float).SetInt(tip), big.NewFloat(1e9))
    fmt.Printf("Zora priority fee: %s Gwei\n", gwei.Text('f', 4))
}
```

## Common Use Cases

### 1. Build an EIP-1559 Transaction

Construct a properly priced type-2 transaction on Zora:

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

async function buildEIP1559Transaction(privateKey, to, valueEth) {
  const wallet = new Wallet(privateKey, provider);

  // Get current fee data
  const feeData = await provider.getFeeData();
  const latestBlock = await provider.getBlock('latest');
  const baseFee = latestBlock.baseFeePerGas;

  // Set maxPriorityFeePerGas from the suggestion
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;

  // maxFeePerGas = 2 * baseFee + maxPriorityFeePerGas (buffer for base fee increases)
  const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas;

  const tx = await wallet.sendTransaction({
    to,
    value: parseEther(valueEth),
    type: 2,
    maxPriorityFeePerGas,
    maxFeePerGas
  });

  console.log('Sent with priority fee:', Number(maxPriorityFeePerGas) / 1e9, 'Gwei');
  return tx;
}
```

### 2. Dynamic Fee Strategy

Adjust priority fees based on transaction urgency:

```javascript
async function getFeeByUrgency(provider, urgency = 'standard') {
  const feeData = await provider.getFeeData();
  const basePriorityFee = feeData.maxPriorityFeePerGas;

  const multipliers = {
    low: 0.8,       // Willing to wait
    standard: 1.0,  // Normal speed
    fast: 1.5,      // Faster inclusion
    urgent: 2.0     // Next-block target
  };

  const multiplier = multipliers[urgency] || 1.0;
  const adjustedFee = BigInt(Math.ceil(Number(basePriorityFee) * multiplier));

  const block = await provider.getBlock('latest');
  const maxFeePerGas = block.baseFeePerGas * 2n + adjustedFee;

  return {
    maxPriorityFeePerGas: adjustedFee,
    maxFeePerGas
  };
}

// Usage
const fees = await getFeeByUrgency(provider, 'fast');
console.log('Priority fee:', Number(fees.maxPriorityFeePerGas) / 1e9, 'Gwei');
console.log('Max fee:', Number(fees.maxFeePerGas) / 1e9, 'Gwei');
```

### 3. Priority Fee Monitor

Track priority fee changes over time on Zora:

```javascript
async function monitorPriorityFee(provider, interval = 12000) {
  let previousFee = null;

  setInterval(async () => {
    const feeData = await provider.getFeeData();
    const currentFee = feeData.maxPriorityFeePerGas;
    const feeGwei = Number(currentFee) / 1e9;

    if (previousFee !== null) {
      const change = Number(currentFee - previousFee) / Number(previousFee) * 100;
      const direction = change > 0 ? 'UP' : change < 0 ? 'DOWN' : 'STABLE';
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei (${direction} ${Math.abs(change).toFixed(1)}%)`);
    } else {
      console.log(`Priority fee: ${feeGwei.toFixed(4)} Gwei`);
    }

    previousFee = currentFee;
  }, interval);
}
```

## Best Practices

- Use `eth_feeHistory` with percentile rewards for a more accurate priority fee estimate than the node's suggestion alone
- The suggested priority fee is the minimum for timely inclusion -- multiply by 1.5-2x for faster confirmation on congested networks
- Fall back to `eth_gasPrice` if `eth_maxPriorityFeePerGas` returns method not found (-32601) on non-EIP-1559 nodes
- For L2 chains, the priority fee is typically much lower than L1 -- never reuse L1 gas parameters on L2
- Cache with a short TTL (12 seconds, one block time) since priority fees change with each block

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/zora/eth_gasPrice) - Get the legacy gas price
- [`eth_feeHistory`](https://www.dwellir.com/docs/zora/eth_feeHistory) - Get historical fee data for trend analysis
- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/zora/eth_getBlockByNumber) - Get block details including `baseFeePerGas`

---

## eth_mining - Zora RPC Method

# eth_mining - Zora RPC Method

Checks the legacy `eth_mining` compatibility method on Zora. Depending on the client behind the endpoint, this call may return a boolean, `unimplemented`, or a method-not-found style error.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

> **Note:** `eth_mining` is best treated as a node-local diagnostic and compatibility probe. Public endpoints often return `false`, `unimplemented`, or a method-not-found error, so it is not a reliable chain-health signal.

## When to Use This Method

`eth_mining` is relevant for NFT creators, digital artists, brands, and onchain media builders:

- **Node Capability Checks** - Verify whether the connected client still exposes this legacy method
- **Migration Audits** - Remove assumptions that Ethereum-era mining RPCs always return a boolean
- **Fallback Design** - Switch dashboards and health probes to `eth_syncing`, `eth_blockNumber`, or `net_version`

## Best Practices

- Returns `false` on proof-of-stake chains (post-Merge) and most modern chains
- Not relevant for provider-managed nodes; do not depend on this for production monitoring
- Use eth\_syncing for general node health checks instead
- Treat unsupported-method and unimplemented responses as a normal condition

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_mining",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): Legacy boolean compatibility value when the connected client still exposes eth_mining

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "unimplemented"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_mining",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_mining',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('eth_mining unsupported:', payload.error.message);
} else {
  console.log('Zora mining:', payload.result);
}

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
try {
  const mining = await provider.send('eth_mining', []);
  console.log('Zora mining:', mining);
} catch (error) {
  console.log('eth_mining unsupported:', error.message);
}
```

```python
import requests

def is_mining():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_mining',
            'params': [],
            'id': 1
        }
    )
    return response.json()

mining = is_mining()
if 'error' in mining:
    print(f"eth_mining unsupported: {mining['error']['message']}")
else:
    print(f'Zora mining: {mining["result"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
try:
    print(f'Zora mining: {w3.eth.mining}')
except Exception as exc:
    print(f'eth_mining unsupported: {exc}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var isMining bool
    err = client.CallContext(context.Background(), &isMining, "eth_mining")
    if err != nil {
        log.Println("eth_mining unsupported:", err)
        return
    }

    fmt.Println("Zora mining:", isMining)
}
```

## Common Use Cases

### 1. Capability-Aware Health Check

Combine `eth_mining` with other status RPCs, but treat unsupported responses as normal:

```javascript
async function getNodeStatus(provider) {
  const [syncing, blockNumber] = await Promise.all([
    provider.send('eth_syncing', []),
    provider.getBlockNumber()
  ]);

  let miningStatus = { supported: false };
  try {
    miningStatus = {
      supported: true,
      result: await provider.send('eth_mining', [])
    };
  } catch {}

  return {
    miningStatus,
    isSynced: syncing === false,
    currentBlock: blockNumber
  };
}
```

### 2. Client Compatibility Check

Check whether the connected client still implements the legacy method:

```javascript
async function checkEthMiningSupport(provider) {
  try {
    const mining = await provider.send('eth_mining', []);
    return { supported: true, mining };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}

const status = await checkEthMiningSupport(provider);
console.log(status);
```

### 3. Recommended Alternatives

For production dashboards and health checks, prefer:

- `eth_blockNumber` for liveness
- `eth_syncing` for sync state
- `net_version` or `eth_chainId` for endpoint identity

## Related Methods

- [`eth_hashrate`](https://www.dwellir.com/docs/zora/eth_hashrate) - Get the mining hash rate
- [`eth_coinbase`](https://www.dwellir.com/docs/zora/eth_coinbase) - Get the coinbase/block producer address
- [`eth_blockNumber`](https://www.dwellir.com/docs/zora/eth_blockNumber) - Get the current block height

---

## eth_newBlockFilter - Zora RPC Method

# eth_newBlockFilter - Zora RPC Method

Creates a filter on Zora that notifies when new blocks arrive. Once created, poll the filter with `eth_getFilterChanges` to receive an array of block hashes for each new block added to the chain since your last poll.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_newBlockFilter` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Block Monitoring** - Detect new blocks on Zora as they are mined or finalized, without repeatedly calling `eth_blockNumber`
- **Chain Progression Tracking** - Build dashboards or alerting systems that track block production rate and timing
- **Reorg Detection** - Identify chain reorganizations by monitoring for blocks that are replaced or missing
- **Event-Driven Architectures** - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

## Best Practices

- Use WebSocket subscriptions (`eth_subscribe`) for real-time block notifications in production environments
- Poll with `eth_getFilterChanges` at 1-5 second intervals to receive new block hashes
- Combine with `eth_getBlockByNumber` or `eth_getBlockByHash` to retrieve full block details

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newBlockFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for new blocks via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte block hashes for each new block since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the block filter
FILTER_ID=$(curl -s -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newBlockFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for new blocks
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a block filter
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Block filter created:', filterId);

// Poll for new blocks
async function pollNewBlocks(interval = 2000) {
  while (true) {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (blockHashes.length > 0) {
      for (const hash of blockHashes) {
        const block = await provider.getBlock(hash);
        console.log(`New block #${block.number} (${hash})`);
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollNewBlocks();
```

```python
import requests
import time

RPC_URL = 'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create block filter
filter_result = rpc_call('eth_newBlockFilter', [])
filter_id = filter_result['result']
print(f'Block filter created: {filter_id}')

# Poll for new blocks
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    block_hashes = changes.get('result', [])
    if block_hashes:
        for block_hash in block_hashes:
            print(f'New block: {block_hash}')
    time.sleep(2)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to new block headers
    headers := make(chan *types.Header)
    sub, err := client.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        // Fallback: polling approach
        lastBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(2 * time.Second)

        for range ticker.C {
            currentBlock, err := client.BlockNumber(context.Background())
            if err != nil {
                log.Println("Error:", err)
                continue
            }
            if currentBlock > lastBlock {
                for b := lastBlock + 1; b <= currentBlock; b++ {
                    block, _ := client.BlockByNumber(context.Background(), new(big.Int).SetUint64(b))
                    if block != nil {
                        fmt.Printf("New block #%d: %s\n", block.Number().Uint64(), block.Hash().Hex())
                    }
                }
                lastBlock = currentBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case header := <-headers:
            fmt.Printf("New block #%d: %s\n", header.Number.Uint64(), header.Hash().Hex())
        }
    }
}
```

## Common Use Cases

### 1. Block Production Rate Monitor

Track block times and detect slowdowns on Zora:

```javascript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}
```

### 2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

```javascript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}
```

### 3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

```javascript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zora/eth_getFilterChanges) - Poll this filter for new block hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zora/eth_uninstallFilter) - Remove the block filter when no longer needed
- [`eth_blockNumber`](https://www.dwellir.com/docs/zora/eth_blockNumber) - Get the current block number (alternative to filter-based monitoring)
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/zora/eth_getBlockByHash) - Fetch full block details for hashes returned by the filter

---

## eth_newFilter - Zora RPC Method

# eth_newFilter - Zora RPC Method

Creates a filter object on Zora based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria - contract addresses, topics, and block ranges. Use `eth_getFilterChanges` to poll for new matching logs or `eth_getFilterLogs` to retrieve all matching logs at once.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_newFilter` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Event Monitoring** - Subscribe to specific contract events on Zora such as token transfers, approvals, or governance votes
- **Contract Activity Tracking** - Watch one or multiple contracts for any emitted events relevant to low-cost NFT minting, onchain media monetization, and creator-owned token economies
- **DeFi Event Streaming** - Monitor swap events, liquidity changes, or oracle price updates in real time
- **Incremental Indexing** - Build event indexes by creating a filter and polling with `eth_getFilterChanges` for only new logs

The filter's block range follows the same plan limits and validation rules as `eth_getLogs`.
See [Rate Limits](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits) before creating a filter over historical blocks.

## Best Practices

- Prefer `eth_getLogs` for one-time queries instead of creating and then immediately uninstalling a filter
- Always call `eth_uninstallFilter` when a filter is no longer needed to free node resources
- Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
- Limit the block range in filter options to avoid query errors on nodes with range restrictions

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block number (hex) or tag ("latest", "earliest", "pending"). Defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Ending block number (hex) or tag. Defaults to "latest"
- `address` (`DATA, required`): No
- `topics` (`Array<DATA, required`): null>

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x4200000000000000000000000000000000000006",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for matching logs via eth_getFilterChanges or eth_getFilterLogs

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1a2b3c"
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter block range too large"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create a filter for Transfer events on a specific contract
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "latest",
      "address": "0x4200000000000000000000000000000000000006",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter for Transfer events
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

console.log('Filter created:', filterId);

// Poll for new events
const interval = setInterval(async () => {
  const logs = await provider.send('eth_getFilterChanges', [filterId]);
  if (logs.length > 0) {
    console.log(`${logs.length} new events found`);
    for (const log of logs) {
      console.log(`  Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
    }
  }
}, 3000);

// Clean up when done
// clearInterval(interval);
// await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests
import time

RPC_URL = 'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for Transfer events
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': 'latest',
    'address': '0x4200000000000000000000000000000000000006',
    'topics': ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}])
filter_id = filter_result['result']
print(f'Filter created: {filter_id}')

# Poll for new events
try:
    while True:
        changes = rpc_call('eth_getFilterChanges', [filter_id])
        logs = changes.get('result', [])
        if logs:
            print(f'{len(logs)} new events found')
            for log in logs:
                block = int(log['blockNumber'], 16)
                print(f'  Block {block}: {log["transactionHash"]}')
        time.sleep(3)
finally:
    # Clean up
    rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"
    "time"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

    // Subscribe to logs (WebSocket) or poll (HTTP)
    logsCh := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
    if err != nil {
        // Fallback: polling
        currentBlock, _ := client.BlockNumber(context.Background())
        ticker := time.NewTicker(3 * time.Second)

        for range ticker.C {
            latestBlock, _ := client.BlockNumber(context.Background())
            if latestBlock > currentBlock {
                query.FromBlock = new(big.Int).SetUint64(currentBlock + 1)
                query.ToBlock = new(big.Int).SetUint64(latestBlock)
                logs, err := client.FilterLogs(context.Background(), query)
                if err == nil {
                    for _, l := range logs {
                        fmt.Printf("Event in block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
                    }
                }
                currentBlock = latestBlock
            }
        }
        return
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case vLog := <-logsCh:
            fmt.Printf("Event in block %d: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
        }
    }
}
```

## Common Use Cases

### 1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Zora:

```javascript
async function monitorTokenTransfers(provider, tokenAddress) {
  // keccak256('Transfer(address,address,uint256)')
  const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: tokenAddress,
    topics: [transferTopic]
  }]);

  console.log(`Monitoring ${tokenAddress} transfers...`);

  setInterval(async () => {
    try {
      const logs = await provider.send('eth_getFilterChanges', [filterId]);

      for (const log of logs) {
        const from = '0x' + log.topics[1].slice(26);
        const to = '0x' + log.topics[2].slice(26);
        const value = BigInt(log.data);

        console.log(`Transfer: ${from} -> ${to} (${value})`);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log('Filter expired - application should recreate');
      }
    }
  }, 3000);

  return filterId;
}
```

### 2. Multi-Event DeFi Monitor

Track multiple event types across DEX contracts:

```javascript
async function monitorDeFiEvents(provider, dexRouterAddress) {
  // Watch for Swap and LiquidityAdded events
  const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
  const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';

  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: 'latest',
    address: dexRouterAddress,
    topics: [[swapTopic, syncTopic]]  // OR matching - either event type
  }]);

  setInterval(async () => {
    const logs = await provider.send('eth_getFilterChanges', [filterId]);

    for (const log of logs) {
      const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
      console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
    }
  }, 2000);

  return filterId;
}
```

### 3. Filter Lifecycle Manager

Manage filter creation, polling, and cleanup with automatic renewal:

```javascript
class FilterManager {
  constructor(provider) {
    this.provider = provider;
    this.filters = new Map();
  }

  async createFilter(name, filterParams, callback) {
    const filterId = await this.provider.send('eth_newFilter', [filterParams]);

    const filter = {
      id: filterId,
      params: filterParams,
      callback,
      interval: setInterval(() => this.poll(name), 3000),
      lastPoll: Date.now()
    };

    this.filters.set(name, filter);
    console.log(`Filter "${name}" created: ${filterId}`);
    return filterId;
  }

  async poll(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    try {
      const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
      filter.lastPoll = Date.now();

      if (logs.length > 0) {
        await filter.callback(logs);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        console.log(`Filter "${name}" expired - recreating...`);
        const newId = await this.provider.send('eth_newFilter', [filter.params]);
        filter.id = newId;
      }
    }
  }

  async removeFilter(name) {
    const filter = this.filters.get(name);
    if (!filter) return;

    clearInterval(filter.interval);
    await this.provider.send('eth_uninstallFilter', [filter.id]);
    this.filters.delete(name);
    console.log(`Filter "${name}" removed`);
  }

  async removeAll() {
    for (const name of this.filters.keys()) {
      await this.removeFilter(name);
    }
  }
}

// Usage
const manager = new FilterManager(provider);

await manager.createFilter('transfers', {
  fromBlock: 'latest',
  address: '0x4200000000000000000000000000000000000006',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zora/eth_getFilterChanges) - Poll this filter for new logs since the last poll
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zora/eth_getFilterLogs) - Get all logs matching this filter at once
- [`eth_getLogs`](https://www.dwellir.com/docs/zora/eth_getLogs) - Query logs directly without creating a filter
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zora/eth_uninstallFilter) - Remove this filter when no longer needed
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zora/eth_newBlockFilter) - Create a filter for new block notifications instead of logs

---

## eth_newPendingTransactionFilter - Zora RPC Method

# eth_newPendingTransactionFilter - Zora RPC Method

Creates a filter on Zora that notifies when new pending transactions are added to the mempool. Once created, poll the filter with `eth_getFilterChanges` to receive an array of transaction hashes for pending transactions that have appeared since your last poll.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_newPendingTransactionFilter` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Mempool Monitoring** - Observe unconfirmed transactions on Zora to understand network activity and congestion
- **Transaction Tracking** - Detect when a specific transaction enters the mempool before it is mined
- **MEV Opportunity Detection** - Identify arbitrage, liquidation, or sandwich opportunities by watching pending transactions
- **Gas Price Estimation** - Analyze pending transactions to estimate optimal gas pricing for low-cost NFT minting, onchain media monetization, and creator-owned token economies

## Best Practices

- High data volume from mempool monitoring requires efficient handling; filter and process selectively
- Use WebSocket `eth_subscribe("newPendingTransactions")` for production-grade pending transaction monitoring
- Pending filter results may include transactions that are never mined; do not treat them as confirmed

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_newPendingTransactionFilter",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): A hex-encoded filter ID used to poll for pending transactions via eth_getFilterChanges
- `result` (`Array<DATA>, required`): Array of 32-byte transaction hashes for pending transactions since the last poll

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x2a1b3c"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Create the pending transaction filter
FILTER_ID=$(curl -s -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newPendingTransactionFilter",
    "params": [],
    "id": 1
  }' | jq -r '.result')

echo "Filter ID: $FILTER_ID"

# Poll for pending transactions
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterChanges\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a pending transaction filter
const filterId = await provider.send('eth_newPendingTransactionFilter', []);
console.log('Pending tx filter created:', filterId);

// Poll for pending transactions
async function pollPendingTxs(interval = 1000) {
  while (true) {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    if (txHashes.length > 0) {
      console.log(`${txHashes.length} new pending transactions`);
      for (const hash of txHashes) {
        const tx = await provider.getTransaction(hash);
        if (tx) {
          console.log(`  ${hash} | to: ${tx.to} | value: ${tx.value}`);
        }
      }
    }
    await new Promise(r => setTimeout(r, interval));
  }
}

pollPendingTxs();
```

```python
import requests
import time

RPC_URL = 'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create pending transaction filter
filter_result = rpc_call('eth_newPendingTransactionFilter', [])
filter_id = filter_result['result']
print(f'Pending tx filter created: {filter_id}')

# Poll for pending transactions
while True:
    changes = rpc_call('eth_getFilterChanges', [filter_id])
    tx_hashes = changes.get('result', [])
    if tx_hashes:
        print(f'{len(tx_hashes)} new pending transactions')
        for tx_hash in tx_hashes[:5]:  # Show first 5
            tx = rpc_call('eth_getTransactionByHash', [tx_hash])
            tx_data = tx.get('result', {})
            if tx_data:
                print(f'  {tx_hash} | to: {tx_data.get("to")} | value: {tx_data.get("value")}')
    time.sleep(1)
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Subscribe to pending transactions
    pendingTxs := make(chan common.Hash)
    sub, err := client.SubscribePendingTransactions(context.Background(), pendingTxs)
    if err != nil {
        log.Fatal("Subscription failed:", err)
    }

    fmt.Println("Monitoring pending transactions on Zora...")

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case txHash := <-pendingTxs:
            tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
            if err == nil && isPending {
                fmt.Printf("Pending tx: %s | to: %s | value: %s\n",
                    txHash.Hex(), tx.To().Hex(), tx.Value().String())
            }
        }
    }
}
```

## Common Use Cases

### 1. Mempool Activity Dashboard

Monitor mempool throughput and transaction types on Zora:

```javascript
async function mempoolDashboard(provider) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);

  const stats = {
    totalSeen: 0,
    contractCalls: 0,
    transfers: 0,
    intervalStart: Date.now()
  };

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);
    stats.totalSeen += txHashes.length;

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        if (tx.data && tx.data !== '0x') {
          stats.contractCalls++;
        } else {
          stats.transfers++;
        }
      } catch (e) {
        // Transaction may have been mined or dropped
      }
    }

    const elapsed = (Date.now() - stats.intervalStart) / 1000;
    const txPerSec = (stats.totalSeen / elapsed).toFixed(1);
    console.log(`Mempool: ${stats.totalSeen} txs (${txPerSec}/s) | Calls: ${stats.contractCalls} | Transfers: ${stats.transfers}`);
  }, 2000);
}
```

### 2. Track Specific Address Activity

Watch for pending transactions involving a target address:

```javascript
async function watchAddress(provider, targetAddress) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const target = targetAddress.toLowerCase();

  console.log(`Watching pending transactions for ${targetAddress}...`);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx) continue;

        const isFrom = tx.from?.toLowerCase() === target;
        const isTo = tx.to?.toLowerCase() === target;

        if (isFrom || isTo) {
          console.log(`Pending tx detected for ${targetAddress}:`);
          console.log(`  Hash: ${hash}`);
          console.log(`  Direction: ${isFrom ? 'OUTGOING' : 'INCOMING'}`);
          console.log(`  Value: ${tx.value} wei`);
          console.log(`  Gas price: ${tx.gasPrice} wei`);
        }
      } catch (e) {
        // Transaction already mined or dropped
      }
    }
  }, 1000);
}
```

### 3. Large Transaction Alert System

Detect high-value pending transactions:

```javascript
async function largeTransactionAlerts(provider, thresholdEth = 10) {
  const filterId = await provider.send('eth_newPendingTransactionFilter', []);
  const thresholdWei = BigInt(thresholdEth * 1e18);

  setInterval(async () => {
    const txHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of txHashes) {
      try {
        const tx = await provider.getTransaction(hash);
        if (!tx || !tx.value) continue;

        if (BigInt(tx.value) >= thresholdWei) {
          const ethValue = Number(BigInt(tx.value)) / 1e18;
          console.log(`LARGE TX: ${ethValue.toFixed(4)} ETH`);
          console.log(`  From: ${tx.from}`);
          console.log(`  To: ${tx.to}`);
          console.log(`  Hash: ${hash}`);
        }
      } catch (e) {
        // Transaction may have already been mined
      }
    }
  }, 1000);
}
```

## Related Methods

- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zora/eth_getFilterChanges) - Poll this filter for new pending transaction hashes
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zora/eth_uninstallFilter) - Remove the filter when no longer needed
- [`eth_getTransactionByHash`](https://www.dwellir.com/docs/zora/eth_getTransactionByHash) - Fetch full transaction details for hashes returned by the filter
- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Submit a transaction that will appear in the pending pool

---

## eth_protocolVersion - Zora RPC Method

# eth_protocolVersion - Zora RPC Method

Returns the current Ethereum protocol version used by the Zora node.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_protocolVersion` is useful for NFT creators, digital artists, brands, and onchain media builders:

- **Client Compatibility** - Verify that a node supports the protocol version your application requires
- **Version-Gated Features** - Enable or disable features based on the protocol version (e.g., EIP-1559 support)
- **Multi-Client Environments** - Ensure consistent protocol versions across a fleet of nodes
- **Debugging** - Diagnose issues caused by protocol version mismatches between clients

## Best Practices

- Modern clients often return a static value; do not rely on this method for feature detection
- This method is not used for transaction signing; use `eth_chainId` for network identification
- Many post-Merge clients no longer support this method; handle unsupported-method errors gracefully

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_protocolVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`STRING, required`): The current Ethereum protocol version as a string (e.g., "0x41" for protocol version 65)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x41"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "the method eth_protocolVersion does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_protocolVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_protocolVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
const version = parseInt(result, 16);
console.log('Zora protocol version:', version);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const protocolVersion = await provider.send('eth_protocolVersion', []);
console.log('Zora protocol version:', parseInt(protocolVersion, 16));
```

```python
import requests

def get_protocol_version():
    response = requests.post(
        'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_protocolVersion',
            'params': [],
            'id': 1
        }
    )
    result = response.json()['result']
    return int(result, 16)

version = get_protocol_version()
print(f'Zora protocol version: {version}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
print(f'Zora protocol version: {w3.eth.protocol_version}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "eth_protocolVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zora protocol version: %s\n", result)
}
```

## Common Use Cases

### 1. Node Compatibility Check

Verify protocol version before enabling features:

```javascript
async function checkCompatibility(provider, minVersion) {
  const result = await provider.send('eth_protocolVersion', []);
  const version = parseInt(result, 16);

  if (version >= minVersion) {
    console.log(`Node supports required protocol version ${minVersion}`);
    return true;
  } else {
    console.warn(`Node protocol version ${version} is below required ${minVersion}`);
    return false;
  }
}
```

### 2. Multi-Node Version Audit

Check protocol consistency across a fleet of Zora nodes:

```javascript
async function auditNodeVersions(endpoints) {
  const results = await Promise.all(
    endpoints.map(async (endpoint) => {
      const provider = new JsonRpcProvider(endpoint);
      const [protocolVersion, clientVersion] = await Promise.all([
        provider.send('eth_protocolVersion', []),
        provider.send('web3_clientVersion', [])
      ]);
      return {
        endpoint,
        protocolVersion: parseInt(protocolVersion, 16),
        clientVersion
      };
    })
  );

  const versions = new Set(results.map(r => r.protocolVersion));
  if (versions.size > 1) {
    console.warn('Protocol version mismatch detected across nodes');
  }

  return results;
}
```

### 3. Feature Detection

Enable features based on the protocol version:

```javascript
async function getNodeCapabilities(provider) {
  try {
    const version = parseInt(await provider.send('eth_protocolVersion', []), 16);

    return {
      protocolVersion: version,
      supportsEIP1559: version >= 65,
      supportsSnapSync: version >= 66
    };
  } catch {
    // Some clients (e.g., post-Merge) may not support this method
    return { protocolVersion: null, supportsEIP1559: true, supportsSnapSync: true };
  }
}
```

zing - retry after delay |
\| -32005 | Rate limit exceeded | Reduce request frequency |

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/zora/web3_clientVersion) - Get the client software version string
- [`net_version`](https://www.dwellir.com/docs/zora/net_version) - Get the network ID
- [`eth_chainId`](https://www.dwellir.com/docs/zora/eth_chainId) - Get the chain ID (EIP-155)

---

## eth_sendRawTransaction - Zora RPC Method

# eth_sendRawTransaction - Zora RPC Method

Submits a pre-signed transaction for broadcast to Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

The `eth_sendRawTransaction` method serves these key scenarios for NFT creators, digital artists, brands, and onchain media builders:

- **Submit pre-signed transactions** - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
- **Broadcast from offline signers** - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Zora
- **Resubmit stuck transactions** - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
- **Deploy contracts programmatically** - Submit contract creation transactions containing compiled bytecode and constructor arguments

## Common Use Cases

### 1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

```javascript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0x4200000000000000000000000000000000000006', '0.01');
```

### 2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Zora mempool.

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');
```

### 3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The `to` field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

```javascript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);
```

## Best Practices

- Always sign transactions client-side: never send private keys to any RPC endpoint, including <https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY>
- Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from `eth_getTransactionCount` with `"pending"` tag before each signing
- The return value is a transaction hash: use `eth_getTransactionReceipt` to poll for confirmation status
- Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
- Use `eth_estimateGas` to set an appropriate gas limit before signing and sending

## Request Parameters

- `signedTransactionData` (`DATA, required`): The signed transaction data (RLP encoded)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendRawTransaction",
  "params": ["0xf86c..."],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): 32-byte transaction hash

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x..."
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendRawTransaction",
    "params": ["0xf86c808504a817c80082520894..."],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

// Send native tokens
async function sendTransaction(to, value) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(value)
  });

  console.log('Transaction hash:', tx.hash);

  // Wait for confirmation
  const receipt = await tx.wait();
  console.log('Confirmed in block:', receipt.blockNumber);

  return receipt;
}

// Send to contract
async function sendContractTransaction(contract, method, args, value = '0') {
  const tx = await contract[method](https://www.dwellir.com/docs/zora/...args, {
    value: parseEther(value)
  });

  return await tx.wait();
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

def send_transaction(private_key, to, value_in_ether):
    account = w3.eth.account.from_key(private_key)

    # Build transaction
    tx = {
        'nonce': w3.eth.get_transaction_count(account.address),
        'to': to,
        'value': w3.to_wei(value_in_ether, 'ether'),
        'gas': 21000,
        'gasPrice': w3.eth.gas_price,
        'chainId': w3.eth.chain_id
    }

    # Sign transaction
    signed_tx = account.sign_transaction(tx)

    # Send transaction
    tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    print(f'Transaction hash: {tx_hash.hex()}')

    # Wait for confirmation
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
    print(f'Confirmed in block: {receipt["blockNumber"]}')

    return receipt
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

    nonce, _ := client.PendingNonceAt(context.Background(), fromAddress)
    value := big.NewInt(1000000000000000000)
    gasLimit := uint64(21000)
    gasPrice, _ := client.SuggestGasPrice(context.Background())

    toAddress := common.HexToAddress("0x4200000000000000000000000000000000000006")
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

    chainID, _ := client.NetworkID(context.Background())
    signedTx, _ := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Transaction hash: %s\n", signedTx.Hash().Hex())
}
```

## Related Methods

- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas required
- [`eth_gasPrice`](https://www.dwellir.com/docs/zora/eth_gasPrice) - Get current gas price
- [`eth_getTransactionReceipt`](https://www.dwellir.com/docs/zora/eth_getTransactionReceipt) - Get transaction result

---

## eth_sendTransaction - Zora RPC Method

# eth_sendTransaction - Zora RPC Method

Creates and sends a new transaction from an unlocked account on Zora. The node signs the transaction server-side using the private key associated with the `from` address.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

> **Security Warning:** Public Dwellir endpoints do not manage unlocked accounts for you. On shared infrastructure, `eth_sendTransaction` commonly returns an unsupported-method response or an account-management error such as `unknown account`, depending on the client. For production applications, **sign transactions client-side** and use [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) instead.

## When to Use This Method

`eth_sendTransaction` is useful for NFT creators, digital artists, brands, and onchain media builders in development scenarios:

- **Local Development** - Send transactions quickly on local nodes (Hardhat, Anvil, Ganache) without managing private keys
- **Testing Workflows** - Rapidly prototype and test contract interactions on dev networks
- **Scripted Deployments** - Deploy contracts on private or permissioned networks with unlocked accounts

## Best Practices

- Requires an unlocked account on the node, which is a significant security risk in production
- Prefer `eth_sendRawTransaction` with client-side signed transactions for all production use cases
- Node-managed accounts are disabled on most public providers; this method is best for local development only

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the sending account (must be unlocked on the node)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `maxFeePerGas` (`QUANTITY, optional`): Maximum total fee per gas (EIP-1559 transactions)
- `maxPriorityFeePerGas` (`QUANTITY, optional`): Maximum priority fee per gas (EIP-1559 transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The transaction hash, or zero hash if the transaction is not yet available

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a"
    }],
    "id": 1
  }'
```

```javascript
// On a local dev node with unlocked accounts (e.g., Hardhat)
const response = await fetch('http://127.0.0.1:8545', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_sendTransaction',
    params: [{
      from: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
      to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
      gas: '0x76c0',
      gasPrice: '0x9184e72a000',
      value: '0x9184e72a'
    }],
    id: 1
  })
});

const { result: txHash } = await response.json();
console.log('Zora tx hash:', txHash);

// Recommended for production: client-side signing
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = await wallet.sendTransaction({
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1')
});
console.log('Zora tx hash:', tx.hash);
```

```python
import requests
from web3 import Web3

# Direct RPC call on a LOCAL dev node with unlocked accounts
response = requests.post(
    'http://127.0.0.1:8545',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_sendTransaction',
        'params': [{
            'from': '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
            'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
            'gas': '0x76c0',
            'gasPrice': '0x9184e72a000',
            'value': '0x9184e72a'
        }],
        'id': 1
    }
)
tx_hash = response.json()['result']
print(f'Zora tx hash: {tx_hash}')

# Recommended for production: client-side signing
w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))
account = w3.eth.account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Zora tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing with eth_sendRawTransaction
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, gasPrice, nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zora tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Local Development with Hardhat

Send transactions using Hardhat's pre-funded unlocked accounts:

```javascript
async function devTransfer(provider, from, to, value) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    to,
    value: '0x' + value.toString(16),
    gas: '0x5208' // 21000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Transfer confirmed in block ${receipt.blockNumber}`);
  return receipt;
}
```

### 2. Contract Deployment on Dev Network

Deploy contracts without managing private keys locally:

```javascript
async function deployContract(provider, from, bytecode) {
  const txHash = await provider.send('eth_sendTransaction', [{
    from,
    data: bytecode,
    gas: '0x4C4B40' // 5,000,000
  }]);

  const receipt = await provider.waitForTransaction(txHash);
  console.log(`Contract deployed at: ${receipt.contractAddress}`);
  return receipt.contractAddress;
}
```

### 3. Batch Transfers in Testing

Send multiple test transactions on Zora dev networks:

```javascript
async function batchTransfer(provider, from, recipients) {
  const hashes = [];

  for (const { to, value } of recipients) {
    const hash = await provider.send('eth_sendTransaction', [{
      from,
      to,
      value: '0x' + value.toString(16),
      gas: '0x5208'
    }]);
    hashes.push(hash);
  }

  return hashes;
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Broadcast a pre-signed transaction (recommended for production)
- [`eth_signTransaction`](https://www.dwellir.com/docs/zora/eth_signTransaction) - Sign without sending (requires unlocked account)
- [`eth_estimateGas`](https://www.dwellir.com/docs/zora/eth_estimateGas) - Estimate gas cost before sending

---

## eth_signTransaction - Zora RPC Method

# eth_signTransaction - Zora RPC Method

Signs a transaction with the private key of the specified account on Zora without submitting it to the network.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

> **Security Warning:** Public Dwellir endpoints do not keep unlocked signers. On shared infrastructure, `eth_signTransaction` commonly returns a deprecation, unsupported-method, or account-management error instead of a signed payload. For production use, **sign transactions client-side** using libraries like [ethers.js](https://docs.ethers.org/) or [web3.py](https://github.com/ethereum/web3.py), then broadcast with [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction).

## When to Use This Method

`eth_signTransaction` is relevant for NFT creators, digital artists, brands, and onchain media builders in limited scenarios:

- **Understanding the Signing Flow** - Learn how transaction signing works before implementing client-side signing
- **Local Development** - Sign transactions on a local dev node (Hardhat, Anvil, Ganache) where accounts are unlocked
- **Offline Signing Workflows** - Generate signed transaction payloads for later broadcast

## Best Practices

- Sign transactions client-side using wallet libraries for production applications
- Never expose private keys to node endpoints; use `eth_sendRawTransaction` with pre-signed transactions
- Use `eth_signTransaction` only in test environments or for air-gapped signing validation

## Request Parameters

- `from` (`DATA (20 bytes), required`): Address of the account to sign with (must be unlocked)
- `to` (`DATA (20 bytes), optional`): Recipient address (omit for contract creation)
- `gas` (`QUANTITY, optional`): Gas limit for the transaction (default: 90000)
- `gasPrice` (`QUANTITY, optional`): Gas price in wei (legacy transactions)
- `value` (`QUANTITY, optional`): Value to send in wei
- `data` (`DATA, optional`): Compiled contract code or encoded method call
- `nonce` (`QUANTITY, optional`): Transaction nonce (defaults to eth_getTransactionCount)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_signTransaction",
  "params": [
    {
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "data": "0x",
      "nonce": "0x0"
    }
  ],
  "id": 1
}
```

## Response Fields

- `raw` (`DATA, required`): The RLP-encoded signed transaction, ready for eth_sendRawTransaction
- `tx` (`Object, required`): The transaction object including v, r, s signature fields

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "raw": "0xf86c808609184e72a0008276c094a94f5374fce5edbc8e2a8697c15331677e6ebf0b849184e72a801ba0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
    "tx": {
      "nonce": "0x0",
      "gasPrice": "0x9184e72a000",
      "gas": "0x76c0",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "value": "0x9184e72a",
      "input": "0x",
      "v": "0x1b",
      "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7571d7c13e32e8ce2c6c8a...",
      "s": "0x3d850e0b25e3c7a3e4da3a7c1b1a4e3b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e..."
    }
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Local dev node only. Public Dwellir endpoints do not expose unlocked-account signing.
curl -X POST http://127.0.0.1:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [{
      "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
      "to": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
      "gas": "0x76c0",
      "gasPrice": "0x9184e72a000",
      "value": "0x9184e72a",
      "nonce": "0x0"
    }],
    "id": 1
  }'
```

```javascript
// Recommended: client-side signing with ethers.js
import { Wallet, JsonRpcProvider, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

const tx = {
  to: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
  value: parseEther('0.1'),
  gasLimit: 21000
};

// Sign without sending
const signedTx = await wallet.signTransaction(tx);
console.log('Signed Zora tx:', signedTx);

// Send later with eth_sendRawTransaction
const receipt = await provider.broadcastTransaction(signedTx);
console.log('Tx hash:', receipt.hash);
```

```python
from web3 import Web3
from eth_account import Account

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Recommended: client-side signing
account = Account.from_key('YOUR_PRIVATE_KEY')

tx = {
    'to': '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
    'value': w3.to_wei(0.1, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': w3.eth.get_transaction_count(account.address),
    'chainId': w3.eth.chain_id
}

signed = account.sign_transaction(tx)
print(f'Signed Zora tx: {signed.raw_transaction.hex()}')

# Send later
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f'Tx hash: {tx_hash.hex()}')
```

```go
package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Recommended: client-side signing
    privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY_HEX")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public().(*ecdsa.PublicKey)
    fromAddress := crypto.PubkeyToAddress(*publicKey)

    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    tx := types.NewTransaction(nonce, toAddress, big.NewInt(100000000), 21000, big.NewInt(10000000000), nil)

    chainID, err := client.ChainID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Signed Zora tx hash: %s\n", signedTx.Hash().Hex())
}
```

## Common Use Cases

### 1. Offline Transaction Signing

Sign transactions on an air-gapped machine for later broadcast:

```javascript
import { Wallet } from 'ethers';

async function createSignedTransaction(privateKey, to, value, { chainId, nonce, gasLimit }) {
  const wallet = new Wallet(privateKey);
  const tx = {
    to,
    value,
    gasLimit,
    nonce,
    chainId,
  };

  const signedTx = await wallet.signTransaction(tx);
  // Store signedTx and broadcast from an online machine
  return signedTx;
}
```

### 2. Batch Transaction Preparation

Pre-sign multiple transactions for sequential submission on Zora:

```javascript
async function prepareBatch(wallet, transactions) {
  const signed = [];

  for (let i = 0; i < transactions.length; i++) {
    const tx = {
      ...transactions[i],
      nonce: baseNonce + i
    };
    signed.push(await wallet.signTransaction(tx));
  }

  return signed; // Submit via eth_sendRawTransaction in order
}
```

## Related Methods

- [`eth_sendRawTransaction`](https://www.dwellir.com/docs/zora/eth_sendRawTransaction) - Broadcast a signed transaction
- [`eth_sendTransaction`](https://www.dwellir.com/docs/zora/eth_sendTransaction) - Sign and send in one step (requires unlocked account)
- [`eth_accounts`](https://www.dwellir.com/docs/zora/eth_accounts) - List accounts available for signing

---

## eth_syncing - Zora RPC Method

# eth_syncing - Zora RPC Method

Returns the sync status of your Zora node - either `false` when fully synced, or an object describing the sync progress.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_syncing` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Node Health Checks** - Verify your node is fully synced before processing transactions
- **Sync Progress Monitoring** - Track how far behind your node is during initial sync or after downtime
- **Load Balancer Routing** - Route requests only to fully synced nodes in multi-node setups
- **dApp Reliability** - Display sync warnings to users when data may be stale

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_syncing",
  "params": [],
  "id": 1
}
```

## Response Fields

- `startingBlock` (`QUANTITY, required`): Block number where sync started
- `currentBlock` (`QUANTITY, required`): Current block being processed
- `highestBlock` (`QUANTITY, required`): Estimated highest block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": false
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_syncing",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const syncing = await provider.send('eth_syncing', []);

if (syncing === false) {
  console.log('Zora node is fully synced');
} else {
  const current = parseInt(syncing.currentBlock, 16);
  const highest = parseInt(syncing.highestBlock, 16);
  const progress = ((current / highest) * 100).toFixed(2);
  console.log(`Syncing: ${progress}% (block ${current} / ${highest})`);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

sync_status = w3.eth.syncing

if sync_status is False:
    print('Zora node is fully synced')
else:
    current = sync_status['currentBlock']
    highest = sync_status['highestBlock']
    progress = (current / highest) * 100
    print(f'Syncing: {progress:.2f}% (block {current} / {highest})')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    progress, err := client.SyncProgress(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    if progress == nil {
        fmt.Println("Zora node is fully synced")
    } else {
        fmt.Printf("Syncing: block %d / %d\n", progress.CurrentBlock, progress.HighestBlock)
    }
}
```

## Common Use Cases

### 1. Node Health Monitor

Continuously check sync status and alert on issues:

```javascript
async function monitorNodeHealth(provider, interval = 30000) {
  setInterval(async () => {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      const blockNumber = await provider.getBlockNumber();
      const block = await provider.getBlock(blockNumber);
      const age = Date.now() / 1000 - block.timestamp;

      if (age > 60) {
        console.warn(`Node synced but block is ${age.toFixed(0)}s old`);
      } else {
        console.log(`Healthy - block ${blockNumber}`);
      }
    } else {
      const current = parseInt(syncing.currentBlock, 16);
      const highest = parseInt(syncing.highestBlock, 16);
      console.warn(`Syncing: ${highest - current} blocks behind`);
    }
  }, interval);
}
```

### 2. Wait for Sync Before Processing

Block application startup until the node is ready:

```javascript
async function waitForSync(provider, pollInterval = 5000) {
  while (true) {
    const syncing = await provider.send('eth_syncing', []);

    if (syncing === false) {
      console.log('Node synced - ready to process transactions');
      return;
    }

    const current = parseInt(syncing.currentBlock, 16);
    const highest = parseInt(syncing.highestBlock, 16);
    console.log(`Waiting for sync: ${highest - current} blocks remaining...`);
    await new Promise(r => setTimeout(r, pollInterval));
  }
}
```

## Best Practices

- Poll `eth_syncing` at application startup and block all transaction operations until `false` is returned
- Check both the sync status AND the latest block timestamp age -- a node can report synced but still have stale data
- In multi-node setups, route read requests to synced nodes and avoid sending transactions to nodes still catching up
- For long-running services, implement a health check that raises alerts if the sync gap exceeds a threshold
- Some client implementations return a sync object with additional fields like `knownStates` and `pulledStates` during state sync

## Related Methods

- [`eth_blockNumber`](https://www.dwellir.com/docs/zora/eth_blockNumber) - Get current block height
- [`net_peerCount`](https://www.dwellir.com/docs/zora/net_peerCount) - Check peer connections
- [`net_listening`](https://www.dwellir.com/docs/zora/net_listening) - Verify node is accepting connections
- [`web3_clientVersion`](https://www.dwellir.com/docs/zora/web3_clientVersion) - Get node client info

---

## eth_uninstallFilter - Zora RPC Method

# eth_uninstallFilter - Zora RPC Method

Removes a filter on Zora that was previously created with `eth_newFilter`, `eth_newBlockFilter`, or `eth_newPendingTransactionFilter`. Should always be called when a filter is no longer needed to free server-side resources.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`eth_uninstallFilter` is important for NFT creators, digital artists, brands, and onchain media builders:

- **Resource Cleanup** - Remove filters you no longer need to free memory and processing on the node
- **Post-Monitoring Teardown** - Clean up after event monitoring sessions end or when switching to different filter criteria
- **Preventing Stale Filters** - Proactively remove filters before they auto-expire to maintain clean state
- **Connection Management** - Uninstall filters before disconnecting to avoid orphaned server-side resources

## Best Practices

- Always uninstall filters in a `finally` block to guarantee cleanup even when errors occur
- Filters expire automatically after a period of inactivity, but explicit uninstallation is more reliable
- Uninstall all active filters when your application shuts down to avoid leaving orphaned resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The ID of the filter to remove (returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_uninstallFilter",
  "params": ["0x1"],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the filter was found and successfully removed, false if the filter ID was not found (already removed or expired)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_uninstallFilter",
    "params": ["0x1"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Create a filter first
const filterId = await provider.send('eth_newBlockFilter', []);
console.log('Created filter:', filterId);

// ... poll with eth_getFilterChanges ...

// Remove the filter when done
const removed = await provider.send('eth_uninstallFilter', [filterId]);
console.log('Filter removed:', removed);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Create a filter
filter_id = w3.eth.filter('latest').filter_id

# ... poll for changes ...

# Remove the filter when done
removed = w3.provider.make_request('eth_uninstallFilter', [filter_id])
print(f'Filter removed: {removed["result"]}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'eth_uninstallFilter',
        'params': ['0x1'],
        'id': 1
    }
)
print(f'Removed: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Create a block filter
    var filterId string
    err = client.CallContext(context.Background(), &filterId, "eth_newBlockFilter")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created filter: %s\n", filterId)

    // Remove the filter
    var removed bool
    err = client.CallContext(context.Background(), &removed, "eth_uninstallFilter", filterId)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Filter removed: %t\n", removed)
}
```

## Common Use Cases

### 1. Filter Lifecycle Manager

Create a managed filter that automatically cleans up:

```javascript
class ManagedFilter {
  constructor(provider) {
    this.provider = provider;
    this.filterId = null;
    this.polling = false;
  }

  async createLogFilter(filterOptions) {
    this.filterId = await this.provider.send('eth_newFilter', [filterOptions]);
    console.log('Filter created:', this.filterId);
    return this.filterId;
  }

  async createBlockFilter() {
    this.filterId = await this.provider.send('eth_newBlockFilter', []);
    return this.filterId;
  }

  async poll() {
    if (!this.filterId) throw new Error('No active filter');
    return await this.provider.send('eth_getFilterChanges', [this.filterId]);
  }

  async destroy() {
    if (this.filterId) {
      const removed = await this.provider.send('eth_uninstallFilter', [this.filterId]);
      console.log(`Filter ${this.filterId} removed: ${removed}`);
      this.filterId = null;
      return removed;
    }
    return false;
  }
}

// Usage
const filter = new ManagedFilter(provider);
await filter.createBlockFilter();

try {
  const changes = await filter.poll();
  console.log('New blocks:', changes);
} finally {
  await filter.destroy();
}
```

### 2. Event Monitor with Cleanup

Monitor events for a limited duration, then clean up all filters:

```javascript
async function monitorEvents(provider, contractAddress, topics, duration = 60000) {
  const filterId = await provider.send('eth_newFilter', [{
    address: contractAddress,
    topics
  }]);

  const allEvents = [];
  const interval = setInterval(async () => {
    const changes = await provider.send('eth_getFilterChanges', [filterId]);
    if (changes.length > 0) {
      allEvents.push(...changes);
      console.log(`Received ${changes.length} new events`);
    }
  }, 2000);

  // Stop monitoring after the specified duration
  await new Promise(r => setTimeout(r, duration));
  clearInterval(interval);

  // Always clean up the filter
  const removed = await provider.send('eth_uninstallFilter', [filterId]);
  console.log(`Monitoring complete. Filter removed: ${removed}. Total events: ${allEvents.length}`);

  return allEvents;
}
```

### 3. Bulk Filter Cleanup

Remove all tracked filters during application shutdown:

```python
import requests

class FilterRegistry:
    def __init__(self, rpc_url):
        self.rpc_url = rpc_url
        self.active_filters = []

    def create_filter(self, filter_type='block'):
        method = {
            'block': 'eth_newBlockFilter',
            'pending': 'eth_newPendingTransactionFilter',
        }.get(filter_type, 'eth_newBlockFilter')

        response = requests.post(
            self.rpc_url,
            json={'jsonrpc': '2.0', 'method': method, 'params': [], 'id': 1}
        )
        filter_id = response.json()['result']
        self.active_filters.append(filter_id)
        return filter_id

    def cleanup_all(self):
        removed = 0
        for filter_id in self.active_filters:
            response = requests.post(
                self.rpc_url,
                json={'jsonrpc': '2.0', 'method': 'eth_uninstallFilter', 'params': [filter_id], 'id': 1}
            )
            if response.json().get('result'):
                removed += 1
        print(f'Cleaned up {removed}/{len(self.active_filters)} filters')
        self.active_filters.clear()
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zora/eth_newFilter) - Create a log event filter
- [`eth_newBlockFilter`](https://www.dwellir.com/docs/zora/eth_newBlockFilter) - Create a new block filter
- [`eth_newPendingTransactionFilter`](https://www.dwellir.com/docs/zora/eth_newPendingTransactionFilter) - Create a pending transaction filter
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zora/eth_getFilterChanges) - Poll a filter for new results
- [`eth_getFilterLogs`](https://www.dwellir.com/docs/zora/eth_getFilterLogs) - Get all logs matching a filter

---

## net_listening - Zora RPC Method

# net_listening - Zora RPC Method

Checks whether the connected Zora client reports that its P2P networking layer is listening for peers. Depending on the client behind the endpoint, this call may return `true`, `false`, or an unsupported-method error.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`net_listening` is useful for NFT creators, digital artists, brands, and onchain media builders:

- **P2P Diagnostics** - Check whether the connected client exposes peer-listening state at all
- **Client Capability Checks** - Distinguish between boolean responses and unsupported-method errors across different node clients
- **Peer-Network Troubleshooting** - Combine with `net_peerCount` and `eth_syncing` when investigating peer discovery or sync issues
- **Operational Audits** - Confirm what the endpoint reports before wiring it into monitoring or dashboards

## Best Practices

- Returns a boolean value only; combine with `net_peerCount` and `eth_syncing` for a comprehensive health check
- A `false` return indicates the node is not accepting network connections
- Some node clients may return an unsupported-method error instead of a boolean; handle both cases

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_listening",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Boolean, required`): true if the client reports that it is listening for peers, false otherwise

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_listening",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

try {
  const listening = await provider.send('net_listening', []);
  console.log('Zora node listening:', listening);
} catch (error) {
  console.log('net_listening unsupported:', error.message);
}

// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_listening',
    params: [],
    id: 1
  })
});

const payload = await response.json();
if (payload.error) {
  console.log('net_listening unsupported:', payload.error.message);
} else {
  console.log('Listening:', payload.result);
}
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

try:
    listening = w3.net.listening
    print(f'Zora node listening: {listening}')
except Exception as exc:
    print(f'net_listening unsupported: {exc}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_listening',
        'params': [],
        'id': 1
    }
)
payload = response.json()
if 'error' in payload:
    print(f"net_listening unsupported: {payload['error']['message']}")
else:
    print(f"Listening: {payload['result']}")
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var listening bool
    err = client.CallContext(context.Background(), &listening, "net_listening")
    if err != nil {
        log.Println("net_listening unsupported:", err)
        return
    }

    fmt.Printf("Zora node listening: %t\n", listening)
}
```

## Common Use Cases

### 1. Capability-Aware Peer Diagnostic

Combine `net_listening` with other status methods, but treat unsupported responses as normal:

```javascript
async function getPeerDiagnostic(provider) {
  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  let listening = { supported: false };
  try {
    listening = { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    listening = { supported: false, message: error.message };
  }

  const peerCount = parseInt(peerCountHex, 16);
  return {
    listening,
    peerCount,
    synced: syncing === false
  };
}
```

### 2. Fallback-Friendly Check

```javascript
async function readListeningStatus(provider) {
  try {
    return { supported: true, value: await provider.send('net_listening', []) };
  } catch (error) {
    return { supported: false, message: error.message };
  }
}
```

### 3. Multi-Node Fleet Monitor

Check which endpoints expose `net_listening` and what they report:

```python
import requests
from concurrent.futures import ThreadPoolExecutor

def check_fleet_listening(endpoints):
    def check_node(endpoint):
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_listening', 'params': [], 'id': 1},
                timeout=5
            )
            payload = response.json()
            if 'error' in payload:
                return {'endpoint': endpoint, 'supported': False, 'error': payload['error']['message']}
            return {'endpoint': endpoint, 'supported': True, 'listening': payload.get('result', False)}
        except Exception as e:
            return {'endpoint': endpoint, 'supported': False, 'error': str(e)}

    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(check_node, endpoints))

    supported = [r for r in results if r.get('supported')]
    unsupported = [r for r in results if not r.get('supported')]

    print(f'{len(supported)}/{len(results)} endpoints expose net_listening')
    for node in unsupported:
        print(f'  UNSUPPORTED: {node["endpoint"]} - {node.get("error", "not available")}')

    return results
```

## Related Methods

- [`net_peerCount`](https://www.dwellir.com/docs/zora/net_peerCount) - Get number of connected peers
- [`net_version`](https://www.dwellir.com/docs/zora/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zora/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/zora/web3_clientVersion) - Get node client info

---

## net_peerCount - Zora RPC Method

# net_peerCount - Zora RPC Method

Returns the number of peers currently connected to your Zora node.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`net_peerCount` is important for NFT creators, digital artists, brands, and onchain media builders:

- **Network Health Monitoring** - Verify your node has sufficient peer connections for reliable data propagation
- **Peer Discovery Verification** - Confirm that peer discovery is working after node startup or network changes
- **Load Balancer Decisions** - Route traffic to well-connected nodes with healthy peer counts
- **Troubleshooting Connectivity** - Diagnose networking issues when a node returns stale or missing data

## Best Practices

- Low peer count may indicate connectivity or firewall issues; investigate if peers drop unexpectedly
- Minimum healthy peer count varies by network; establish baselines for your specific Zora deployment
- Combine with `eth_syncing` for a complete picture of node health and readiness

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_peerCount",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`QUANTITY, required`): Hexadecimal string representing the number of connected peers

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x19"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_peerCount does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_peerCount",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const peerCountHex = await provider.send('net_peerCount', []);
const peerCount = parseInt(peerCountHex, 16);
console.log(`Zora peers: ${peerCount}`);

// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_peerCount',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Peers:', parseInt(result, 16));
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

peer_count = w3.net.peer_count
print(f'Zora peers: {peer_count}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_peerCount',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Peers: {int(result, 16)}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var result string
    err = client.CallContext(context.Background(), &result, "net_peerCount")
    if err != nil {
        log.Fatal(err)
    }

    peerCount := new(big.Int)
    peerCount.SetString(result[2:], 16)
    fmt.Printf("Zora peers: %s\n", peerCount.String())
}
```

## Common Use Cases

### 1. Network Health Monitor

Continuously check peer count and alert when it drops below a threshold:

```javascript
async function monitorPeers(provider, minPeers = 3, interval = 30000) {
  setInterval(async () => {
    const peerCountHex = await provider.send('net_peerCount', []);
    const peerCount = parseInt(peerCountHex, 16);

    if (peerCount === 0) {
      console.error('CRITICAL: Node has no peers - network isolated');
    } else if (peerCount < minPeers) {
      console.warn(`LOW PEERS: ${peerCount} connected (minimum: ${minPeers})`);
    } else {
      console.log(`Healthy - ${peerCount} peers connected`);
    }
  }, interval);
}
```

### 2. Node Readiness Check

Verify a node has enough peers before routing traffic to it:

```javascript
async function isNodeReady(rpcUrl, minPeers = 5) {
  const provider = new JsonRpcProvider(rpcUrl);

  const [peerCountHex, syncing] = await Promise.all([
    provider.send('net_peerCount', []),
    provider.send('eth_syncing', [])
  ]);

  const peerCount = parseInt(peerCountHex, 16);
  const isSynced = syncing === false;
  const hasEnoughPeers = peerCount >= minPeers;

  return {
    ready: isSynced && hasEnoughPeers,
    peerCount,
    syncing: !isSynced
  };
}
```

### 3. Multi-Node Fleet Dashboard

Aggregate peer counts across a fleet of Zora nodes:

```python
import requests

def check_fleet_peers(endpoints):
    results = []
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'net_peerCount', 'params': [], 'id': 1},
                timeout=5
            )
            peers = int(response.json()['result'], 16)
            results.append({'endpoint': endpoint, 'peers': peers, 'healthy': peers > 0})
        except Exception as e:
            results.append({'endpoint': endpoint, 'peers': 0, 'healthy': False, 'error': str(e)})
    return results
```

## Related Methods

- [`net_listening`](https://www.dwellir.com/docs/zora/net_listening) - Check if node is accepting connections
- [`net_version`](https://www.dwellir.com/docs/zora/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zora/eth_syncing) - Check node sync progress
- [`web3_clientVersion`](https://www.dwellir.com/docs/zora/web3_clientVersion) - Get node client info

---

## net_version - Zora RPC Method

# net_version - Zora RPC Method

Returns the current network ID on Zora as a decimal string. The network ID identifies which network the node is connected to.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`net_version` is essential for NFT creators, digital artists, brands, and onchain media builders:

- **Endpoint Identification** - Confirm your application is connected to the expected Zora network
- **Multi-Chain App Routing** - Dynamically detect which network an RPC endpoint serves and route logic accordingly
- **Connection Validation** - Perform a quick sanity check during node or provider initialization

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "net_version",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): The current network ID as a decimal string (e.g., "1" for Ethereum mainnet, "5" for Goerli)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "1"
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "The method net_version does not exist/is not available"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "net_version",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const networkId = await provider.send('net_version', []);
console.log('Zora network ID:', networkId);

// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'net_version',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Network ID:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

network_id = w3.net.version
print(f'Zora network ID: {network_id}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'net_version',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Network ID: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var networkId string
    err = client.CallContext(context.Background(), &networkId, "net_version")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zora network ID: %s\n", networkId)
}
```

## Common Use Cases

### 1. Multi-Chain Connection Validator

Verify your application connects to the expected network before processing any transactions:

```javascript
const EXPECTED_NETWORKS = {
  '1': 'Ethereum Mainnet',
  '137': 'Polygon',
  '42161': 'Arbitrum One',
  '10': 'Optimism',
};

async function validateNetwork(provider, expectedNetworkId) {
  const networkId = await provider.send('net_version', []);

  if (networkId !== expectedNetworkId) {
    const actual = EXPECTED_NETWORKS[networkId] || `Unknown (${networkId})`;
    const expected = EXPECTED_NETWORKS[expectedNetworkId] || expectedNetworkId;
    throw new Error(`Wrong network: connected to ${actual}, expected ${expected}`);
  }

  console.log(`Connected to ${EXPECTED_NETWORKS[networkId]}`);
  return networkId;
}
```

### 2. Dynamic Chain Router

Route application logic based on the detected network:

```javascript
async function createChainRouter(rpcUrl) {
  const provider = new JsonRpcProvider(rpcUrl);
  const networkId = await provider.send('net_version', []);

  const config = {
    '1': { explorer: 'https://etherscan.io', confirmations: 12 },
    '137': { explorer: 'https://polygonscan.com', confirmations: 128 },
    '42161': { explorer: 'https://arbiscan.io', confirmations: 1 },
  };

  if (!config[networkId]) {
    throw new Error(`Unsupported network ID: ${networkId}`);
  }

  return { provider, networkId, ...config[networkId] };
}
```

### 3. Network ID vs Chain ID Comparison

Compare `net_version` with `eth_chainId` when you need both endpoint identity and signing context:

```python
from web3 import Web3

def verify_chain_identity(rpc_url):
    w3 = Web3(Web3.HTTPProvider(rpc_url))

    network_id = int(w3.net.version)
    chain_id = w3.eth.chain_id

    if network_id != chain_id:
        print(f'Network ID ({network_id}) differs from chain ID ({chain_id})')
    else:
        print(f'Network and chain ID match: {chain_id}')

    print('Use eth_chainId as the signing source of truth')

    return {'network_id': network_id, 'chain_id': chain_id}
```

## Best Practices

- Use `eth_chainId` for transaction signing (EIP-155 replay protection) -- `net_version` is for network identification only
- Cache the network ID at startup -- it does not change during a session
- Some L2 and sidechain networks share the same network ID as their L1 -- always combine with `eth_chainId` for unambiguous identification
- For multi-chain dApps, maintain a mapping of network IDs to chain-specific contract addresses and RPC endpoints
- The `net_*` namespace may be disabled on some node configurations -- handle the -32601 error gracefully

## Related Methods

- [`eth_chainId`](https://www.dwellir.com/docs/zora/eth_chainId) - Get the EIP-155 chain ID (preferred for transaction signing)
- [`net_listening`](https://www.dwellir.com/docs/zora/net_listening) - Check whether the client reports peer-listening state
- [`net_peerCount`](https://www.dwellir.com/docs/zora/net_peerCount) - Get number of connected peers
- [`eth_syncing`](https://www.dwellir.com/docs/zora/eth_syncing) - Check node sync progress

---

## rollup_gasPrices - Get L2 gas price oracle data

# rollup_gasPrices - Get L2 gas price oracle data

Get L2 gas price oracle data on the Zora OP Stack network. This method is essential for understanding gas pricing dynamics on Zora's L2, including both execution and data availability costs.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_gasPrices",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): L1 gas price (for data availability) L2 gas price (for execution) Scalar multiplier Overhead values

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "l1GasPrice": "0x5d21dba00",
    "l2GasPrice": "0x5f5e100",
    "l1BaseFee": "0x5d21dba00",
    "overhead": "0xbc",
    "scalar": "0x10000000000000000000000000000000"
  }
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_gasPrices",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_gasPrices',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## rollup_getInfo - Get rollup configuration

# rollup_getInfo - Get rollup configuration

Get rollup configuration information for the Zora OP Stack L2 network. This method provides essential configuration data about the rollup including version information, chain parameters, and network-specific settings.

## Request Parameters

This method accepts no parameters.

## Request Example

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "rollup_getInfo",
        "params": [],
        "id": 1
      }'
```

## Response Fields

- `result` (`OBJECT, required`): Rollup version and implementation details Chain configuration parameters L1 and L2 relationship information Network-specific settings for creator economy features

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "mode": "sequencer",
    "syncing": false,
    "sequencerEnabled": true,
    "ethContext": {
      "blockNumber": 18750000,
      "blockHash": "0x1234567890abcdef...",
      "timestamp": 1701234567
    },
    "rollupContext": {
      "index": 1500000,
      "queueIndex": 750000,
      "verifiedIndex": 1450000
    }
  }
}
```

## Implementation Example

cURL
JavaScript

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rollup_getInfo",
    "params": [],
    "id": 1
  }'
```

```javascript
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'rollup_getInfo',
    params: [],
    id: 1
  })
});

const data = await response.json();
console.log(data.result);
```

---

## rpc_modules - Zora RPC Method

# rpc_modules - Zora RPC Method

Returns the enabled JSON-RPC namespaces exposed by the connected Zora endpoint together with their version strings.

> **Non-standard method.** `rpc_modules` is a client-introspection RPC that is commonly available on Geth-compatible stacks, but it is not part of the core Ethereum Execution API method set. Availability varies by client and operator policy.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`rpc_modules` is useful for NFT creators, digital artists, brands, and onchain media builders:

- **Capability Discovery** - Detect whether namespaces like `debug`, `trace`, `txpool`, or `erigon` are exposed before attempting those calls
- **Client Diagnostics** - Verify what the serving node has enabled when debugging environment-specific issues
- **Infrastructure Audits** - Compare public and private endpoints to confirm which RPC surfaces are intentionally exposed
- **Runtime Feature Gating** - Adjust tooling behavior dynamically based on the actual namespaces available on a node

## Best Practices

- Call at startup to determine which features are available on a node
- Module availability varies by node client and provider configuration
- Use to gate feature access in applications before attempting unsupported calls
- This is a non-standard method; some endpoints may not expose it

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "rpc_modules",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Object, required`): Object whose keys are enabled namespaces and whose values are version strings

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "eth": "1.0",
    "net": "1.0",
    "web3": "1.0",
    "rpc": "1.0",
    "debug": "1.0",
    "trace": "1.0",
    "txpool": "1.0"
  }
}
```

## Error Responses

### Error Response

- Code: `-32601`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "rpc_modules",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const modules = await provider.send('rpc_modules', []);
console.log('Namespaces:', Object.keys(modules));

if (modules.debug) {
  console.log('Debug RPC is enabled');
}
```

```python
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'rpc_modules',
        'params': [],
        'id': 1,
    },
)

modules = response.json()['result']
print('Namespaces:', sorted(modules.keys()))
print('Has trace:', 'trace' in modules)
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "sort"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var modules map[string]string
    err = client.CallContext(context.Background(), &modules, "rpc_modules")
    if err != nil {
        log.Fatal(err)
    }

    names := make([]string, 0, len(modules))
    for name := range modules {
        names = append(names, name)
    }
    sort.Strings(names)
    fmt.Printf("Namespaces: %v\n", names)
}
```

## Related Methods

- [`web3_clientVersion`](https://www.dwellir.com/docs/zora/web3_clientVersion) - Inspect the client software version string
- [`debug_traceTransaction`](https://www.dwellir.com/docs/zora/debug_traceTransaction) - Debug namespace example
- `trace_transaction` - Trace namespace example

---

## web3_clientVersion - Zora RPC Method

# web3_clientVersion - Zora RPC Method

Returns the current client software version string for your Zora node, including the client name, version number, OS, and runtime.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

## When to Use This Method

`web3_clientVersion` is valuable for NFT creators, digital artists, brands, and onchain media builders:

- **Client Compatibility Checks** - Verify the node runs a client version that supports the RPC methods your application needs
- **Fleet Version Monitoring** - Track client versions across a multi-node infrastructure to coordinate upgrades
- **Debugging Client-Specific Behavior** - Identify which client (Geth, Erigon, Nethermind, Besu, etc.) is serving requests when behavior differs
- **Security Auditing** - Detect nodes running outdated versions with known vulnerabilities

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_clientVersion",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): Client version string, typically in the format ClientName/vX.Y.Z/OS/Runtime

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "Geth/v1.13.5-stable/linux-amd64/go1.21.4"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_clientVersion",
    "params": [],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

const clientVersion = await provider.send('web3_clientVersion', []);
console.log('Zora client:', clientVersion);

// Using fetch
const response = await fetch('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'web3_clientVersion',
    params: [],
    id: 1
  })
});

const { result } = await response.json();
console.log('Client version:', result);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

client_version = w3.client_version
print(f'Zora client: {client_version}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_clientVersion',
        'params': [],
        'id': 1
    }
)
result = response.json()['result']
print(f'Client version: {result}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    var clientVersion string
    err = client.CallContext(context.Background(), &clientVersion, "web3_clientVersion")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Zora client: %s\n", clientVersion)
}
```

## Common Use Cases

### 1. Client Version Parser

Parse the version string to extract structured information:

```javascript
function parseClientVersion(versionString) {
  const parts = versionString.split('/');

  return {
    client: parts[0],
    version: parts[1] || 'unknown',
    os: parts[2] || 'unknown',
    runtime: parts[3] || 'unknown'
  };
}

async function getNodeInfo(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const parsed = parseClientVersion(version);

  console.log(`Client: ${parsed.client}`);
  console.log(`Version: ${parsed.version}`);
  console.log(`OS: ${parsed.os}`);
  console.log(`Runtime: ${parsed.runtime}`);

  return parsed;
}
```

### 2. Fleet Version Audit

Check all nodes in a fleet and report version inconsistencies:

```python
import requests

def audit_fleet_versions(endpoints):
    versions = {}
    for endpoint in endpoints:
        try:
            response = requests.post(
                endpoint,
                json={'jsonrpc': '2.0', 'method': 'web3_clientVersion', 'params': [], 'id': 1},
                timeout=5
            )
            version = response.json()['result']
            versions[endpoint] = version
        except Exception as e:
            versions[endpoint] = f'ERROR: {e}'

    # Group by client version
    grouped = {}
    for endpoint, version in versions.items():
        grouped.setdefault(version, []).append(endpoint)

    for version, nodes in grouped.items():
        print(f'{version}: {len(nodes)} node(s)')

    if len(grouped) > 1:
        print('WARNING: Inconsistent versions detected across fleet')

    return versions
```

### 3. Feature Detection by Client

Adjust RPC behavior based on the detected client type:

```javascript
async function detectClientCapabilities(provider) {
  const version = await provider.send('web3_clientVersion', []);
  const client = version.split('/')[0].toLowerCase();

  const capabilities = {
    supportsDebugTrace: ['geth', 'erigon'].includes(client),
    supportsParityTrace: ['openethereum', 'nethermind', 'erigon'].includes(client),
    supportsEthSubscribe: true, // all modern clients
  };

  console.log(`Client "${client}" capabilities:`, capabilities);
  return capabilities;
}
```

## Best Practices

- Parse the client version string at startup and log it for debugging -- different clients may handle edge cases differently
- Maintain a fleet inventory that tracks client versions and flags nodes running outdated software
- When reporting issues to node providers, always include the `web3_clientVersion` output
- Some clients expose additional features based on version -- check version strings for feature gates (e.g., Erigon 3.x supports `ots_*` namespace)
- The version string format varies across clients -- avoid hardcoding assumptions about the delimiter or field count

## Related Methods

- [`net_version`](https://www.dwellir.com/docs/zora/net_version) - Get the network ID
- [`eth_syncing`](https://www.dwellir.com/docs/zora/eth_syncing) - Check node sync progress
- [`web3_sha3`](https://www.dwellir.com/docs/zora/web3_sha3) - Compute Keccak-256 hash via RPC
- [`net_peerCount`](https://www.dwellir.com/docs/zora/net_peerCount) - Get number of connected peers

---

## web3_sha3 - Zora RPC Method

# web3_sha3 - Zora RPC Method

Returns the Keccak-256 hash (not standard SHA3-256) of the given data on Zora.

> **Why Zora?** Build on the creator-first L2 powering $353M+ in NFT trading volume with 179K+ active creators with 0.000777 ETH minting fees, 50% creator royalty share, no-code NFT toolkit, and OP Stack Ethereum security.

**Important**: Despite the method name, `web3_sha3` computes Keccak-256, which differs from the NIST-standardized SHA3-256. Ethereum adopted Keccak before NIST finalized the SHA-3 standard with different padding.

## When to Use This Method

`web3_sha3` is helpful for NFT creators, digital artists, brands, and onchain media builders:

- **Hash Verification** - Confirm that your local Keccak-256 implementation matches the node's output
- **Smart Contract Development** - Compute function selectors and event topic hashes needed for ABI encoding
- **Data Integrity Checks** - Hash data server-side via RPC and compare against expected values
- **Debugging** - Verify hashing results when troubleshooting transaction or contract interactions

## Best Practices

- Input data must be hex-encoded with a `0x` prefix; plain text strings will cause errors
- Use for quick Keccak-256 hashing without a client-side library, but prefer local hashing for performance
- Compute function selectors by taking the first 4 bytes of the hash result

## Request Parameters

- `data` (`DATA, required`): The hex-encoded data to hash (must be 0x prefixed)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "web3_sha3",
  "params": ["0x68656c6c6f"],
  "id": 1
}
```

## Response Fields

- `result` (`DATA, required`): The Keccak-256 hash of the provided data (32 bytes, 0x prefixed)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex string without 0x prefix"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "web3_sha3",
    "params": ["0x68656c6c6f"],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes, hexlify } from 'ethers';

const provider = new JsonRpcProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY');

// Using RPC
const hash = await provider.send('web3_sha3', ['0x68656c6c6f']);
console.log('RPC hash:', hash);

// Using ethers locally (faster, no network call)
const localHash = keccak256(toUtf8Bytes('hello'));
console.log('Local hash:', localHash);

// Verify they match
console.log('Match:', hash === localHash);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Using RPC
data = '0x68656c6c6f'  # "hello" in hex
rpc_hash = w3.provider.make_request('web3_sha3', [data])['result']
print(f'RPC hash: {rpc_hash}')

# Using web3.py locally (faster)
local_hash = w3.keccak(text='hello').hex()
print(f'Local hash: 0x{local_hash}')

# Using requests directly
import requests

response = requests.post(
    'https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY',
    json={
        'jsonrpc': '2.0',
        'method': 'web3_sha3',
        'params': ['0x68656c6c6f'],
        'id': 1
    }
)
print(f'Hash: {response.json()["result"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    "golang.org/x/crypto/sha3"
)

func main() {
    client, err := rpc.Dial("https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Using RPC
    var rpcHash string
    err = client.CallContext(context.Background(), &rpcHash, "web3_sha3", "0x68656c6c6f")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("RPC hash: %s\n", rpcHash)

    // Using local Keccak-256
    hasher := sha3.NewLegacyKeccak256()
    hasher.Write([]byte("hello"))
    localHash := fmt.Sprintf("0x%x", hasher.Sum(nil))
    fmt.Printf("Local hash: %s\n", localHash)
}
```

## Common Use Cases

### 1. Function Selector Computation

Compute Solidity function selectors for ABI encoding:

```javascript
async function getFunctionSelector(provider, signature) {
  // Convert signature to hex
  const hexSignature = '0x' + Buffer.from(signature).toString('hex');

  // Hash via RPC
  const hash = await provider.send('web3_sha3', [hexSignature]);

  // Function selector is the first 4 bytes
  const selector = hash.slice(0, 10);
  console.log(`${signature} => ${selector}`);
  return selector;
}

// Example: compute selectors for common ERC-20 functions
const selectors = {
  'transfer(address,uint256)': await getFunctionSelector(provider, 'transfer(address,uint256)'),
  'balanceOf(address)': await getFunctionSelector(provider, 'balanceOf(address)'),
  'approve(address,uint256)': await getFunctionSelector(provider, 'approve(address,uint256)'),
};
```

### 2. Hash Verification Between Local and RPC

Verify your local hashing matches the node to catch library misconfigurations:

```javascript
async function verifyHashingConsistency(provider) {
  const testCases = [
    { input: '0x', label: 'empty bytes' },
    { input: '0x68656c6c6f', label: '"hello"' },
    { input: '0x0123456789abcdef', label: 'hex data' },
  ];

  for (const { input, label } of testCases) {
    const rpcHash = await provider.send('web3_sha3', [input]);
    const localHash = keccak256(input);

    const match = rpcHash === localHash;
    console.log(`${label}: ${match ? 'PASS' : 'FAIL'}`);

    if (!match) {
      console.error(`  RPC:   ${rpcHash}`);
      console.error(`  Local: ${localHash}`);
    }
  }
}
```

### 3. Event Topic Hash Generation

Generate event topic hashes for filtering logs:

```python
from web3 import Web3

def get_event_topic(w3, event_signature):
    """Generate the topic hash for an event signature."""
    hex_sig = '0x' + event_signature.encode().hex()
    result = w3.provider.make_request('web3_sha3', [hex_sig])
    return result['result']

w3 = Web3(Web3.HTTPProvider('https://api-zora-mainnet.n.dwellir.com/YOUR_API_KEY'))

# Common ERC-20 event topics
topics = {
    'Transfer(address,address,uint256)': get_event_topic(w3, 'Transfer(address,address,uint256)'),
    'Approval(address,address,uint256)': get_event_topic(w3, 'Approval(address,address,uint256)'),
}

for sig, topic in topics.items():
    print(f'{sig}\n  => {topic}')
```

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/zora/eth_call) - Execute a call without creating a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/zora/eth_getCode) - Get contract bytecode at an address
- [`web3_clientVersion`](https://www.dwellir.com/docs/zora/web3_clientVersion) - Get node client version

---

